From 7a48f923b8b27bfaa5f7b2a449a6fe268724ddd5 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 17 Jan 2006 11:51:28 -0800 Subject: [SCTP]: Fix potential race condition between sctp_close() and sctp_rcv(). Do not release the reference to association/endpoint if an incoming skb is added to backlog. Instead release it after the chunk is processed in sctp_backlog_rcv(). Signed-off-by: Sridhar Samudrala Signed-off-by: Vlad Yasevich --- net/sctp/input.c | 29 ++++++++++++++++++++--------- net/sctp/inqueue.c | 4 +++- 2 files changed, 23 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index 4aa6fc60357c..c463e4049c52 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -262,15 +262,12 @@ int sctp_rcv(struct sk_buff *skb) else sctp_backlog_rcv(sk, skb); - /* Release the sock and any reference counts we took in the - * lookup calls. + /* Release the sock and the sock ref we took in the lookup calls. + * The asoc/ep ref will be released in sctp_backlog_rcv. */ sctp_bh_unlock_sock(sk); - if (asoc) - sctp_association_put(asoc); - else - sctp_endpoint_put(ep); sock_put(sk); + return ret; discard_it: @@ -296,9 +293,23 @@ discard_release: int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; - struct sctp_inq *inqueue = &chunk->rcvr->inqueue; - - sctp_inq_push(inqueue, chunk); + struct sctp_inq *inqueue = NULL; + struct sctp_ep_common *rcvr = NULL; + + rcvr = chunk->rcvr; + if (rcvr->dead) { + sctp_chunk_free(chunk); + } else { + inqueue = &chunk->rcvr->inqueue; + sctp_inq_push(inqueue, chunk); + } + + /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ + if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) + sctp_association_put(sctp_assoc(rcvr)); + else + sctp_endpoint_put(sctp_ep(rcvr)); + return 0; } diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 2d33922c044b..297b8951463e 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue) /* If there is a packet which is currently being worked on, * free it as well. */ - if (queue->in_progress) + if (queue->in_progress) { sctp_chunk_free(queue->in_progress); + queue->in_progress = NULL; + } if (queue->malloced) { /* Dump the master memory segment. */ -- cgit v1.2.3 From 9834a2bb4970547540222fcba04e0a37d04cb0a0 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 17 Jan 2006 11:52:12 -0800 Subject: [SCTP]: Fix sctp_cookie alignment in the packet. On 64 bit architectures, sctp_cookie sent as part of INIT-ACK is not aligned on a 64 bit boundry and thus causes unaligned access exceptions. The layout of the cookie prameter is this: |<----- Parameter Header --------------------|<--- Cookie DATA -------- ----------------------------------------------------------------------- | param type (16 bits) | param len (16 bits) | sig [32 bytes] | cookie.. ----------------------------------------------------------------------- The cookie data portion contains 64 bit values on 64 bit architechtures (timeval) that fall on a 32 bit alignment boundry when used as part of the on-wire format, but align correctly when used in internal structures. This patch explicitely pads the on-wire format so that it is properly aligned. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala --- include/net/sctp/structs.h | 3 ++- net/sctp/sm_make_chunk.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index f5c22d77feab..72aeae4a0067 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -405,8 +405,9 @@ struct sctp_cookie { /* The format of our cookie that we send to our peer. */ struct sctp_signed_cookie { __u8 signature[SCTP_SECRET_SIZE]; + __u32 __pad; /* force sctp_cookie alignment to 64 bits */ struct sctp_cookie c; -}; +} __attribute__((packed)); /* This is another convenience type to allocate memory for address * params for the maximum size and pass such structures around diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 556c495c6922..4fe1d6c863b1 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1275,7 +1275,12 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, unsigned int keylen; char *key; - headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; + /* Header size is static data prior to the actual cookie, including + * any padding. + */ + headersize = sizeof(sctp_paramhdr_t) + + (sizeof(struct sctp_signed_cookie) - + sizeof(struct sctp_cookie)); bodysize = sizeof(struct sctp_cookie) + ntohs(init_chunk->chunk_hdr->length) + addrs_len; @@ -1362,7 +1367,12 @@ struct sctp_association *sctp_unpack_cookie( struct sk_buff *skb = chunk->skb; struct timeval tv; - headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; + /* Header size is static data prior to the actual cookie, including + * any padding. + */ + headersize = sizeof(sctp_chunkhdr_t) + + (sizeof(struct sctp_signed_cookie) - + sizeof(struct sctp_cookie)); bodysize = ntohs(chunk->chunk_hdr->length) - headersize; fixed_size = headersize + sizeof(struct sctp_cookie); -- cgit v1.2.3 From 49392e5ecf608da6770fd8723b534a0fc851edc4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 17 Jan 2006 11:53:06 -0800 Subject: [SCTP]: sctp doesn't show all associations/endpoints in /proc When creating a very large number of associations (and endpoints), /proc/assocs and /proc/eps will not show all of them. As a result netstat will not show all of the either. This is particularly evident when creating 1000+ associations (or endpoints). As an example with 1500 tcp style associations over loopback, netstat showed 1420 on my system instead of 3000. The reason for this is that the seq_operations start method is invoked multiple times bacause of the amount of data that is provided. The start method always increments the position parameter and since we use the position as the hash bucket id, we end up skipping hash buckets. This patch corrects this situation and get's rid of the silly hash-1 decrement. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala --- net/sctp/proc.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 6e4dc28874d7..1b5e5b119f79 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -176,7 +176,7 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) { - if (*pos > sctp_ep_hashsize) + if (*pos >= sctp_ep_hashsize) return NULL; if (*pos < 0) @@ -185,8 +185,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n"); - ++*pos; - return (void *)pos; } @@ -198,11 +196,9 @@ static void sctp_eps_seq_stop(struct seq_file *seq, void *v) static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - if (*pos > sctp_ep_hashsize) + if (++*pos >= sctp_ep_hashsize) return NULL; - ++*pos; - return pos; } @@ -216,17 +212,17 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) struct sock *sk; int hash = *(int *)v; - if (hash > sctp_ep_hashsize) + if (hash >= sctp_ep_hashsize) return -ENOMEM; - head = &sctp_ep_hashtable[hash-1]; + head = &sctp_ep_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { ep = sctp_ep(epb); sk = epb->sk; seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, - sctp_sk(sk)->type, sk->sk_state, hash-1, + sctp_sk(sk)->type, sk->sk_state, hash, epb->bind_addr.port, sock_i_uid(sk), sock_i_ino(sk)); @@ -283,7 +279,7 @@ void sctp_eps_proc_exit(void) static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) { - if (*pos > sctp_assoc_hashsize) + if (*pos >= sctp_assoc_hashsize) return NULL; if (*pos < 0) @@ -293,8 +289,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " "RPORT LADDRS <-> RADDRS\n"); - ++*pos; - return (void *)pos; } @@ -306,11 +300,9 @@ static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - if (*pos > sctp_assoc_hashsize) + if (++*pos >= sctp_assoc_hashsize) return NULL; - ++*pos; - return pos; } @@ -323,10 +315,10 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) struct sock *sk; int hash = *(int *)v; - if (hash > sctp_assoc_hashsize) + if (hash >= sctp_assoc_hashsize) return -ENOMEM; - head = &sctp_assoc_hashtable[hash-1]; + head = &sctp_assoc_hashtable[hash]; sctp_local_bh_disable(); read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { @@ -335,7 +327,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", assoc, sk, sctp_sk(sk)->type, sk->sk_state, - assoc->state, hash-1, assoc->assoc_id, + assoc->state, hash, assoc->assoc_id, (sk->sk_rcvbuf - assoc->rwnd), assoc->sndbuf_used, sock_i_uid(sk), sock_i_ino(sk), -- cgit v1.2.3 From 38b0e42aba928d9929a26ec23b850c36a31fca5f Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 17 Jan 2006 11:54:06 -0800 Subject: [SCTP]: Fix sctp_assoc_seq_show() panics on big-endian systems. This patch corrects the panic by casting the argument to the pointer of correct size. On big-endian systems we ended up loading only 32 bits of data because we are treating the pointer as an int*. By treating this pointer as loff_t*, we'll load the full 64 bits and then let regular integer demotion take place which will give us the correct value. Signed-off-by: Vlad Yaseivch Signed-off-by: Sridhar Samudrala --- net/sctp/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 1b5e5b119f79..d47a52c303a8 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -210,7 +210,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_endpoint *ep; struct sock *sk; - int hash = *(int *)v; + int hash = *(loff_t *)v; if (hash >= sctp_ep_hashsize) return -ENOMEM; @@ -313,7 +313,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) struct sctp_ep_common *epb; struct sctp_association *assoc; struct sock *sk; - int hash = *(int *)v; + int hash = *(loff_t *)v; if (hash >= sctp_assoc_hashsize) return -ENOMEM; -- cgit v1.2.3 From 8116ffad4180b39d7a755345c1fde09da83930c0 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 17 Jan 2006 11:55:17 -0800 Subject: [SCTP]: Fix bad sysctl formatting of SCTP timeout values on 64-bit m/cs. Change all the structure members that hold jiffies to be of type unsigned long. This also corrects bad sysctl formating on 64 bit architectures. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala --- include/net/sctp/structs.h | 78 ++++++++++++++++++++++++---------------------- net/sctp/sm_sideeffect.c | 4 +-- net/sctp/socket.c | 2 +- net/sctp/sysctl.c | 7 ++--- net/sctp/transport.c | 2 +- 5 files changed, 47 insertions(+), 46 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 72aeae4a0067..ad3d15cb0a0d 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -127,9 +127,9 @@ extern struct sctp_globals { * RTO.Alpha - 1/8 (3 when converted to right shifts.) * RTO.Beta - 1/4 (2 when converted to right shifts.) */ - __u32 rto_initial; - __u32 rto_min; - __u32 rto_max; + unsigned long rto_initial; + unsigned long rto_min; + unsigned long rto_max; /* Note: rto_alpha and rto_beta are really defined as inverse * powers of two to facilitate integer operations. @@ -140,12 +140,18 @@ extern struct sctp_globals { /* Max.Burst - 4 */ int max_burst; - /* Valid.Cookie.Life - 60 seconds */ - int valid_cookie_life; - /* Whether Cookie Preservative is enabled(1) or not(0) */ int cookie_preserve_enable; + /* Valid.Cookie.Life - 60 seconds */ + unsigned long valid_cookie_life; + + /* Delayed SACK timeout 200ms default*/ + unsigned long sack_timeout; + + /* HB.interval - 30 seconds */ + unsigned long hb_interval; + /* Association.Max.Retrans - 10 attempts * Path.Max.Retrans - 5 attempts (per destination address) * Max.Init.Retransmits - 8 attempts @@ -168,12 +174,6 @@ extern struct sctp_globals { */ int rcvbuf_policy; - /* Delayed SACK timeout 200ms default*/ - int sack_timeout; - - /* HB.interval - 30 seconds */ - int hb_interval; - /* The following variables are implementation specific. */ /* Default initialization values to be applied to new associations. */ @@ -828,7 +828,7 @@ struct sctp_transport { __u32 rtt; /* This is the most recent RTT. */ /* RTO : The current retransmission timeout value. */ - __u32 rto; + unsigned long rto; /* RTTVAR : The current RTT variation. */ __u32 rttvar; @@ -878,22 +878,10 @@ struct sctp_transport { /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to * the destination address every heartbeat interval. */ - __u32 hbinterval; - - /* This is the max_retrans value for the transport and will - * be initialized from the assocs value. This can be changed - * using SCTP_SET_PEER_ADDR_PARAMS socket option. - */ - __u16 pathmaxrxt; - - /* PMTU : The current known path MTU. */ - __u32 pathmtu; + unsigned long hbinterval; /* SACK delay timeout */ - __u32 sackdelay; - - /* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */ - __u32 param_flags; + unsigned long sackdelay; /* When was the last time (in jiffies) that we heard from this * transport? We use this to pick new active and retran paths. @@ -905,6 +893,18 @@ struct sctp_transport { */ unsigned long last_time_ecne_reduced; + /* This is the max_retrans value for the transport and will + * be initialized from the assocs value. This can be changed + * using SCTP_SET_PEER_ADDR_PARAMS socket option. + */ + __u16 pathmaxrxt; + + /* PMTU : The current known path MTU. */ + __u32 pathmtu; + + /* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */ + __u32 param_flags; + /* The number of times INIT has been sent on this transport. */ int init_sent_count; @@ -1500,9 +1500,9 @@ struct sctp_association { * These values will be initialized by system defaults, but can * be modified via the SCTP_RTOINFO socket option. */ - __u32 rto_initial; - __u32 rto_max; - __u32 rto_min; + unsigned long rto_initial; + unsigned long rto_max; + unsigned long rto_min; /* Maximum number of new data packets that can be sent in a burst. */ int max_burst; @@ -1520,13 +1520,13 @@ struct sctp_association { __u16 init_retries; /* The largest timeout or RTO value to use in attempting an INIT */ - __u16 max_init_timeo; + unsigned long max_init_timeo; /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to * the destination address every heartbeat interval. This value * will be inherited by all new transports. */ - __u32 hbinterval; + unsigned long hbinterval; /* This is the max_retrans value for new transports in the * association. @@ -1538,13 +1538,14 @@ struct sctp_association { */ __u32 pathmtu; - /* SACK delay timeout */ - __u32 sackdelay; - /* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */ __u32 param_flags; - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + /* SACK delay timeout */ + unsigned long sackdelay; + + + unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; /* Transport to which SHUTDOWN chunk was last sent. */ @@ -1649,7 +1650,10 @@ struct sctp_association { /* How many duplicated TSNs have we seen? */ int numduptsns; - /* Number of seconds of idle time before an association is closed. */ + /* Number of seconds of idle time before an association is closed. + * In the association context, this is really used as a boolean + * since the real timeout is stored in the timeouts array + */ __u32 autoclose; /* These are to support diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index b8b38aba92b3..8d1dc24bab4c 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1300,7 +1300,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, "T1 INIT Timeout adjustment" " init_err_counter: %d" " cycle: %d" - " timeout: %d\n", + " timeout: %ld\n", asoc->init_err_counter, asoc->init_cycle, asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]); @@ -1328,7 +1328,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, SCTP_DEBUG_PRINTK( "T1 COOKIE Timeout adjustment" " init_err_counter: %d" - " timeout: %d\n", + " timeout: %ld\n", asoc->init_err_counter, asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c98ee375ba5e..6a0b1af89932 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2995,7 +2995,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hbinterval = jiffies_to_msecs(sctp_hb_interval); sp->pathmaxrxt = sctp_max_retrans_path; sp->pathmtu = 0; // allow default discovery - sp->sackdelay = sctp_sack_timeout; + sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout); sp->param_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE | SPP_SACKDELAY_ENABLE; diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index fcd7096c953d..dc6f3ff32358 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -159,12 +159,9 @@ static ctl_table sctp_table[] = { .ctl_name = NET_SCTP_PRESERVE_ENABLE, .procname = "cookie_preserve_enable", .data = &sctp_cookie_preserve_enable, - .maxlen = sizeof(long), + .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_doulongvec_ms_jiffies_minmax, - .strategy = &sctp_sysctl_jiffies_ms, - .extra1 = &rto_timer_min, - .extra2 = &rto_timer_max + .proc_handler = &proc_dointvec }, { .ctl_name = NET_SCTP_RTO_ALPHA, diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 68d73e2dd155..160f62ad1cc5 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -350,7 +350,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) tp->rto_pending = 0; SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d " - "rttvar: %d, rto: %d\n", __FUNCTION__, + "rttvar: %d, rto: %ld\n", __FUNCTION__, tp, rtt, tp->srtt, tp->rttvar, tp->rto); } -- cgit v1.2.3 From 313e7b4d2588539e388d31c1febd50503a0083fc Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 17 Jan 2006 11:55:57 -0800 Subject: [SCTP]: Fix machine check/connection hang on IA64. sctp_unpack_cookie used an on-stack array called digest as a result/out parameter in the call to crypto_hmac. However, hmac code (crypto_hmac_final) assumes that the 'out' argument is in virtual memory (identity mapped region) and can use virt_to_page call on it. This does not work with the on-stack declared digest. The problems observed so far have been: a) incorrect hmac digest b) machine check and hardware reset. Solution is to define the digest in an identity mapped region by kmalloc'ing it. We can do this once as part of the endpoint structure and re-use it when verifying the SCTP cookie. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala --- include/net/sctp/structs.h | 8 ++++++++ net/sctp/sm_make_chunk.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ad3d15cb0a0d..8c522ae031bb 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1250,6 +1250,14 @@ struct sctp_endpoint { int last_key; int key_changed_at; + /* digest: This is a digest of the sctp cookie. This field is + * only used on the receive path when we try to validate + * that the cookie has not been tampered with. We put + * this here so we pre-allocate this once and can re-use + * on every receive. + */ + __u8 digest[SCTP_SIGNATURE_SIZE]; + /* sendbuf acct. policy. */ __u32 sndbuf_policy; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 4fe1d6c863b1..5e0de3c0eead 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1359,7 +1359,7 @@ struct sctp_association *sctp_unpack_cookie( struct sctp_signed_cookie *cookie; struct sctp_cookie *bear_cookie; int headersize, bodysize, fixed_size; - __u8 digest[SCTP_SIGNATURE_SIZE]; + __u8 *digest = ep->digest; struct scatterlist sg; unsigned int keylen, len; char *key; -- cgit v1.2.3 From c4d2444e992c4eda1d7fc3287e93ba58295bf6b9 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 17 Jan 2006 11:56:26 -0800 Subject: [SCTP]: Fix couple of races between sctp_peeloff() and sctp_rcv(). Validate and update the sk in sctp_rcv() to avoid the race where an assoc/ep could move to a different socket after we get the sk, but before the skb is added to the backlog. Also migrate the skb's in backlog queue to new sk when doing a peeloff. Signed-off-by: Sridhar Samudrala --- include/net/sctp/sctp.h | 2 ++ net/sctp/input.c | 35 ++++++++++++++++++++++++++++++++++- net/sctp/socket.c | 4 ++++ 3 files changed, 40 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index a553f39f6aee..e673b2c984e9 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -175,6 +175,8 @@ void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, void sctp_icmp_proto_unreachable(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t); +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk); /* * Section: Macros, externs, and inlines diff --git a/net/sctp/input.c b/net/sctp/input.c index c463e4049c52..71fd56375641 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -257,12 +257,21 @@ int sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); + /* It is possible that the association could have moved to a different + * socket if it is peeled off. If so, update the sk. + */ + if (sk != rcvr->sk) { + sctp_bh_lock_sock(rcvr->sk); + sctp_bh_unlock_sock(sk); + sk = rcvr->sk; + } + if (sock_owned_by_user(sk)) sk_add_backlog(sk, skb); else sctp_backlog_rcv(sk, skb); - /* Release the sock and the sock ref we took in the lookup calls. + /* Release the sock and the sock ref we took in the lookup calls. * The asoc/ep ref will be released in sctp_backlog_rcv. */ sctp_bh_unlock_sock(sk); @@ -297,6 +306,9 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) struct sctp_ep_common *rcvr = NULL; rcvr = chunk->rcvr; + + BUG_TRAP(rcvr->sk == sk); + if (rcvr->dead) { sctp_chunk_free(chunk); } else { @@ -313,6 +325,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) return 0; } +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk) +{ + struct sk_buff *skb; + struct sctp_chunk *chunk; + + skb = oldsk->sk_backlog.head; + oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL; + while (skb != NULL) { + struct sk_buff *next = skb->next; + + chunk = SCTP_INPUT_CB(skb)->chunk; + skb->next = NULL; + if (&assoc->base == chunk->rcvr) + sk_add_backlog(newsk, skb); + else + sk_add_backlog(oldsk, skb); + skb = next; + } +} + /* Handle icmp frag needed error. */ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t, __u32 pmtu) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6a0b1af89932..fb1821d9f338 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5602,8 +5602,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ newsp->type = type; + spin_lock_bh(&oldsk->sk_lock.slock); + /* Migrate the backlog from oldsk to newsk. */ + sctp_backlog_migrate(assoc, oldsk, newsk); /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); + spin_unlock_bh(&oldsk->sk_lock.slock); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. -- cgit v1.2.3 From a7d1f1b66c05ef4ebb58a34be7caad9af15546a4 Mon Sep 17 00:00:00 2001 From: Tsutomu Fujii Date: Tue, 17 Jan 2006 11:57:09 -0800 Subject: [SCTP]: Fix sctp_rcv_ootb() to handle the last chunk of a packet correctly. Signed-off-by: Tsutomu Fujii Signed-off-by: Sridhar Samudrala --- net/sctp/input.c | 13 +++++++++---- net/sctp/sm_statefuns.c | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index 71fd56375641..cb78b50868ee 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -588,10 +588,16 @@ int sctp_rcv_ootb(struct sk_buff *skb) sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; - ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); /* Scan through all the chunks in the packet. */ - while (ch_end > (__u8 *)ch && ch_end < skb->tail) { + do { + /* Break out if chunk length is less then minimal. */ + if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) + break; + + ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + if (ch_end > skb->tail) + break; /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the * receiver MUST silently discard the OOTB packet and take no @@ -622,8 +628,7 @@ int sctp_rcv_ootb(struct sk_buff *skb) } ch = (sctp_chunkhdr_t *) ch_end; - ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); - } + } while (ch_end < skb->tail); return 0; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 477d7f80dba6..71c9a961c321 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3090,6 +3090,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, break; ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + if (ch_end > skb->tail) + break; if (SCTP_CID_SHUTDOWN_ACK == ch->type) ootb_shut_ack = 1; -- cgit v1.2.3 From 2966b66c25f81ad2b3298b651614c6a3be1a977f Mon Sep 17 00:00:00 2001 From: Kris Katterjohn Date: Mon, 23 Jan 2006 16:26:16 -0800 Subject: [NET]: more whitespace issues in net/core/filter.c This fixes some whitespace issues in net/core/filter.c Signed-off-by: Kris Katterjohn Signed-off-by: David S. Miller --- net/core/filter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/filter.c b/net/core/filter.c index 9540946a48f3..93fbd01d2259 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -64,7 +64,7 @@ static inline void *load_pointer(struct sk_buff *skb, int k, } /** - * sk_run_filter - run a filter on a socket + * sk_run_filter - run a filter on a socket * @skb: buffer to run the filter on * @filter: filter to apply * @flen: length of filter @@ -78,8 +78,8 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int { struct sock_filter *fentry; /* We walk down these */ void *ptr; - u32 A = 0; /* Accumulator */ - u32 X = 0; /* Index Register */ + u32 A = 0; /* Accumulator */ + u32 X = 0; /* Index Register */ u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */ u32 tmp; int k; -- cgit v1.2.3 From 8ae55f0489d9a3446fcdaf4ffedda249234b8572 Mon Sep 17 00:00:00 2001 From: Kris Katterjohn Date: Mon, 23 Jan 2006 16:28:02 -0800 Subject: [NET]: Fix some whitespace issues in af_packet.c Signed-off-by: Kris Katterjohn Signed-off-by: David S. Miller --- net/packet/af_packet.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ee93abc71cb8..9db7dbdb16e6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -365,7 +365,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ err = -EMSGSIZE; - if(len>dev->mtu+dev->hard_header_len) + if (len > dev->mtu + dev->hard_header_len) goto out_unlock; err = -ENOBUFS; @@ -935,7 +935,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add * Check legality */ - if(addr_len!=sizeof(struct sockaddr)) + if (addr_len != sizeof(struct sockaddr)) return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); @@ -1092,7 +1092,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, * retries. */ - if(skb==NULL) + if (skb == NULL) goto out; /* @@ -1392,8 +1392,8 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, if (level != SOL_PACKET) return -ENOPROTOOPT; - if (get_user(len,optlen)) - return -EFAULT; + if (get_user(len, optlen)) + return -EFAULT; if (len < 0) return -EINVAL; @@ -1419,9 +1419,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, return -ENOPROTOOPT; } - if (put_user(len, optlen)) - return -EFAULT; - return 0; + if (put_user(len, optlen)) + return -EFAULT; + return 0; } -- cgit v1.2.3 From 8798b3fb714477f5c88dde102c149d2b3e1d8def Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 23 Jan 2006 16:32:45 -0800 Subject: [NET]: Fix skb fclone error path handling. On the error path if we allocated an fclone then we will free it in the wrong pool. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d0732e9c8560..6766f118f070 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -135,13 +135,15 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here) struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, int fclone) { + kmem_cache_t *cache; struct skb_shared_info *shinfo; struct sk_buff *skb; u8 *data; + cache = fclone ? skbuff_fclone_cache : skbuff_head_cache; + /* Get the HEAD */ - skb = kmem_cache_alloc(fclone ? skbuff_fclone_cache : skbuff_head_cache, - gfp_mask & ~__GFP_DMA); + skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA); if (!skb) goto out; @@ -180,7 +182,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, out: return skb; nodata: - kmem_cache_free(skbuff_head_cache, skb); + kmem_cache_free(cache, skb); skb = NULL; goto out; } -- cgit v1.2.3 From cabcac0b296cd9683bc168d60839729b720dc2b7 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 24 Jan 2006 12:46:33 -0800 Subject: [BONDING]: Remove CAP_NET_ADMIN requirement for INFOQUERY ioctl This information is already available via /proc/net/bonding/* therefore it doesn't make sense to require CAP_NET_ADMIN privileges. Original patch by Laurent Deniel Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index fd070a098f20..ffb82073056e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2543,13 +2543,14 @@ int dev_ioctl(unsigned int cmd, void __user *arg) case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: case SIOCBONDCHANGEACTIVE: case SIOCBRADDIF: case SIOCBRDELIF: if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* fall through */ + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: dev_load(ifr.ifr_name); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); -- cgit v1.2.3 From 151bb0ffe51514979abf54063bb5c1dd49365137 Mon Sep 17 00:00:00 2001 From: Jerome Borsboom Date: Tue, 24 Jan 2006 12:57:19 -0800 Subject: [AF_KEY]: no message type set When returning a message to userspace in reply to a SADB_FLUSH or SADB_X_SPDFLUSH message, the type was not set for the returned PFKEY message. The patch below corrects this problem. Signed-off-by: Jerome Borsboom Signed-off-by: David S. Miller --- net/key/af_key.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/key/af_key.c b/net/key/af_key.c index 43f1ce74187d..ae86d237a456 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1620,6 +1620,7 @@ static int key_notify_sa_flush(struct km_event *c) return -ENOBUFS; hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto); + hdr->sadb_msg_type = SADB_FLUSH; hdr->sadb_msg_seq = c->seq; hdr->sadb_msg_pid = c->pid; hdr->sadb_msg_version = PF_KEY_V2; @@ -2385,6 +2386,7 @@ static int key_notify_policy_flush(struct km_event *c) if (!skb_out) return -ENOBUFS; hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); + hdr->sadb_msg_type = SADB_X_SPDFLUSH; hdr->sadb_msg_seq = c->seq; hdr->sadb_msg_pid = c->pid; hdr->sadb_msg_version = PF_KEY_V2; -- cgit v1.2.3 From 7add2a439868d636910fb6a216b12c7392778956 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Tue, 24 Jan 2006 13:06:39 -0800 Subject: [IPV6] MLDv2: fix change records when transitioning to/from inactive The following patch fixes these problems in MLDv2: 1) Add/remove "delete" records for sending change reports when addition of a filter results in that filter transitioning to/from inactive. [same as recent IPv4 IGMPv3 fix] 2) Remove 2 redundant "group_type" checks (can't be IPV6_ADDR_ANY within that loop, so checks are always true) 3) change an is_in() "return 0" to "return type == MLD2_MODE_IS_INCLUDE". It should always be "0" to get here, but it improves code locality to not assume it, and if some race allowed otherwise, doing the check would return the correct result. Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- net/ipv6/mcast.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 6c05c7978bef..4420948a1bfe 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1252,8 +1252,7 @@ int igmp6_event_query(struct sk_buff *skb) } } else { for (ma = idev->mc_list; ma; ma=ma->next) { - if (group_type != IPV6_ADDR_ANY && - !ipv6_addr_equal(group, &ma->mca_addr)) + if (!ipv6_addr_equal(group, &ma->mca_addr)) continue; spin_lock_bh(&ma->mca_lock); if (ma->mca_flags & MAF_TIMER_RUNNING) { @@ -1268,11 +1267,10 @@ int igmp6_event_query(struct sk_buff *skb) ma->mca_flags &= ~MAF_GSQUERY; } if (!(ma->mca_flags & MAF_GSQUERY) || - mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) + mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) igmp6_group_queried(ma, max_delay); spin_unlock_bh(&ma->mca_lock); - if (group_type != IPV6_ADDR_ANY) - break; + break; } } read_unlock_bh(&idev->lock); @@ -1351,7 +1349,7 @@ static int is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type, * in all filters */ if (psf->sf_count[MCAST_INCLUDE]) - return 0; + return type == MLD2_MODE_IS_INCLUDE; return pmc->mca_sfcount[MCAST_EXCLUDE] == psf->sf_count[MCAST_EXCLUDE]; } @@ -1966,7 +1964,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc) static int sf_setstate(struct ifmcaddr6 *pmc) { - struct ip6_sf_list *psf; + struct ip6_sf_list *psf, *dpsf; int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; int qrv = pmc->idev->mc_qrv; int new_in, rv; @@ -1978,8 +1976,48 @@ static int sf_setstate(struct ifmcaddr6 *pmc) !psf->sf_count[MCAST_INCLUDE]; } else new_in = psf->sf_count[MCAST_INCLUDE] != 0; - if (new_in != psf->sf_oldin) { - psf->sf_crcount = qrv; + if (new_in) { + if (!psf->sf_oldin) { + struct ip6_sf_list *prev = 0; + + for (dpsf=pmc->mca_tomb; dpsf; + dpsf=dpsf->sf_next) { + if (ipv6_addr_equal(&dpsf->sf_addr, + &psf->sf_addr)) + break; + prev = dpsf; + } + if (dpsf) { + if (prev) + prev->sf_next = dpsf->sf_next; + else + pmc->mca_tomb = dpsf->sf_next; + kfree(dpsf); + } + psf->sf_crcount = qrv; + rv++; + } + } else if (psf->sf_oldin) { + psf->sf_crcount = 0; + /* + * add or update "delete" records if an active filter + * is now inactive + */ + for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next) + if (ipv6_addr_equal(&dpsf->sf_addr, + &psf->sf_addr)) + break; + if (!dpsf) { + dpsf = (struct ip6_sf_list *) + kmalloc(sizeof(*dpsf), GFP_ATOMIC); + if (!dpsf) + continue; + *dpsf = *psf; + /* pmc->mca_lock held by callers */ + dpsf->sf_next = pmc->mca_tomb; + pmc->mca_tomb = dpsf; + } + dpsf->sf_crcount = qrv; rv++; } } -- cgit v1.2.3 From b6daa25d653f23252b340cbd7d2153d0b338e44c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 19 Jan 2006 16:20:42 +0800 Subject: [PATCH] ieee80211: Fix problem with not decrypting broadcast packets The code for pulling the key to use for decrypt was correctly using the host_mc_decrypt flag. The code that actually decrypted, however, was based on host_decrypt. This patch changes this behavior. Signed-off-by: Etay Bogner Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_rx.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 7a121802faa9..695d0478fd12 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -350,6 +350,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, u8 src[ETH_ALEN]; struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; + int can_be_decrypted = 0; hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; @@ -410,12 +411,23 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 1; } - if (is_multicast_ether_addr(hdr->addr1) - ? ieee->host_mc_decrypt : ieee->host_decrypt) { + can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr2)) ? + ieee->host_mc_decrypt : ieee->host_decrypt; + + if (can_be_decrypted) { int idx = 0; - if (skb->len >= hdrlen + 3) + if (skb->len >= hdrlen + 3) { + /* Top two-bits of byte 3 are the key index */ idx = skb->data[hdrlen + 3] >> 6; + } + + /* ieee->crypt[] is WEP_KEY (4) in length. Given that idx + * is only allowed 2-bits of storage, no value of idx can + * be provided via above code that would result in idx + * being out of range */ crypt = ieee->crypt[idx]; + #ifdef NOT_YET sta = NULL; @@ -553,7 +565,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ - if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && + if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) goto rx_dropped; @@ -617,7 +629,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* skb: hdr + (possible reassembled) full MSDU payload; possibly still * encrypted/authenticated */ - if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && + if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) goto rx_dropped; -- cgit v1.2.3 From 55cd94aa1df8e575ab3236641d29d63ecdde5012 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 19 Jan 2006 16:20:59 +0800 Subject: [PATCH] ieee80211: Fix iwlist scan can only show about 20 APs Limit the amount of output given to iwlist scan. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_wx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 23e1630f50b7..f87c6b89f845 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -232,15 +232,18 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee, return start; } +#define SCAN_ITEM_SIZE 128 + int ieee80211_wx_get_scan(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ieee80211_network *network; unsigned long flags; + int err = 0; char *ev = extra; - char *stop = ev + IW_SCAN_MAX_DATA; + char *stop = ev + wrqu->data.length; int i = 0; IEEE80211_DEBUG_WX("Getting scan\n"); @@ -249,6 +252,11 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, list_for_each_entry(network, &ieee->network_list, list) { i++; + if (stop - ev < SCAN_ITEM_SIZE) { + err = -E2BIG; + break; + } + if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) ev = ipw2100_translate_scan(ieee, ev, stop, network); @@ -270,7 +278,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); - return 0; + return err; } int ieee80211_wx_set_encode(struct ieee80211_device *ieee, -- cgit v1.2.3 From 1a1fedf4d3e27c920b8de92a429011fb11c89028 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 30 Jan 2006 09:42:24 -0600 Subject: [PATCH] Typo corrections for ieee80211 This patch, generated against 2.6.16-rc1-git4, corrects two typographical errors in ieee80211_rx.c and adds the facility name to a bare printk. Signed-Off-By: Larry Finger Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 695d0478fd12..960aa78cdb97 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -1451,7 +1451,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, break; case IEEE80211_STYPE_PROBE_REQ: - IEEE80211_DEBUG_MGMT("recieved auth (%d)\n", + IEEE80211_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); @@ -1485,7 +1485,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, break; case IEEE80211_STYPE_AUTH: - IEEE80211_DEBUG_MGMT("recieved auth (%d)\n", + IEEE80211_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); -- cgit v1.2.3 From 81845c21dc1ec7ce2bf12845dbc01e4880f9ea9a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 30 Jan 2006 15:59:54 -0800 Subject: [SCTP]: correct the number of INIT retransmissions We currently count the initial INIT/COOKIE_ECHO chunk toward the retransmit count and thus sends a total of sctp_max_retrans_init chunks. The correct behavior is to retransmit the chunk sctp_max_retrans_init in addition to sending the original. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 6 +++--- net/sctp/socket.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 71c9a961c321..018f169a50e9 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2122,7 +2122,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, struct sctp_bind_addr *bp; int attempts = asoc->init_err_counter + 1; - if (attempts >= asoc->max_init_attempts) { + if (attempts > asoc->max_init_attempts) { sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_STALE_COOKIE)); return SCTP_DISPOSITION_DELETE_TCB; @@ -4640,7 +4640,7 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep, SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n"); - if (attempts < asoc->max_init_attempts) { + if (attempts <= asoc->max_init_attempts) { bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); if (!repl) @@ -4697,7 +4697,7 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n"); - if (attempts < asoc->max_init_attempts) { + if (attempts <= asoc->max_init_attempts) { repl = sctp_make_cookie_echo(asoc, NULL); if (!repl) return SCTP_DISPOSITION_NOMEM; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fb1821d9f338..0ea947eb6813 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5426,7 +5426,7 @@ out: return err; do_error: - if (asoc->init_err_counter + 1 >= asoc->max_init_attempts) + if (asoc->init_err_counter + 1 > asoc->max_init_attempts) err = -ETIMEDOUT; else err = -ECONNREFUSED; -- cgit v1.2.3 From e2c2fc2c8f3750e1f7ffbb3ac2b885a49416110c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 30 Jan 2006 16:00:40 -0800 Subject: [SCTP]: heartbeats exceed maximum retransmssion limit The number of HEARTBEAT chunks that an association may transmit is limited by Association.Max.Retrans count; however, the code allows us to send one extra heartbeat. This patch limits the number of heartbeats to the maximum count. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 018f169a50e9..2b9a832b29a7 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -884,7 +884,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, { struct sctp_transport *transport = (struct sctp_transport *) arg; - if (asoc->overall_error_count > asoc->max_retrans) { + if (asoc->overall_error_count >= asoc->max_retrans) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); -- cgit v1.2.3 From c5d90e000437a463440c1fe039011a02583a9ee5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 30 Jan 2006 20:27:17 -0800 Subject: [IPV4] igmp: remove pointless printk This is easily triggerable by sending bogus packets, allowing a malicious user to flood remote logs. Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d8ce7133cd8f..f70ba622c856 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -970,7 +970,6 @@ int igmp_rcv(struct sk_buff *skb) case IGMP_MTRACE_RESP: break; default: - NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type); } drop: -- cgit v1.2.3 From 2c74088e4104a2a82bd773f79ae0344c22eceb8c Mon Sep 17 00:00:00 2001 From: Baruch Even Date: Mon, 30 Jan 2006 20:54:39 -0800 Subject: [TCP] H-TCP: Fix accounting This fixes the accounting in H-TCP, the ccount variable is also adjusted a few lines above this one. This line was not supposed to be there and wasn't there in the patches originally submitted, the four patches submitted were merged to one and in that merge the bug was introduced. Signed-Off-By: Baruch Even Signed-off-by: David S. Miller --- net/ipv4/tcp_htcp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 3284cfb993e6..128de4d7c0b7 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -230,7 +230,6 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; tp->snd_cwnd_cnt = 0; - ca->ccount++; } } } -- cgit v1.2.3 From dd1c1853e2742f4938b271dbe0cee735e2ffa3d9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 31 Jan 2006 13:11:41 -0800 Subject: Fix ipv4/igmp.c compile with gcc-4 and IP_MULTICAST Modern versions of gcc do not like case statements at the end of a block statement: you need at least an empty statement. Using just a "break;" is preferred for visual style. Signed-off-by: Linus Torvalds --- net/ipv4/igmp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index f70ba622c856..0b4e95f93dad 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -970,6 +970,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMP_MTRACE_RESP: break; default: + break; } drop: -- cgit v1.2.3 From 5d39a795bfa217b5f7637028c83ab5cb291f37bf Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 31 Jan 2006 17:35:35 -0800 Subject: [IPV4]: Always set fl.proto in ip_route_newports ip_route_newports uses the struct flowi from the struct rtable returned by ip_route_connect for the new route lookup and just replaces the port numbers if they have changed. If an IPsec policy exists which doesn't match port 0 the struct flowi won't have the proto field set and no xfrm lookup is done for the changed ports. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/route.h | 5 +++-- net/dccp/ipv4.c | 3 ++- net/ipv4/tcp_ipv4.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/route.h b/include/net/route.h index e3e5436f8017..9c04f15090d2 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -170,8 +170,8 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, return ip_route_output_flow(rp, &fl, sk, 0); } -static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport, - struct sock *sk) +static inline int ip_route_newports(struct rtable **rp, u8 protocol, + u16 sport, u16 dport, struct sock *sk) { if (sport != (*rp)->fl.fl_ip_sport || dport != (*rp)->fl.fl_ip_dport) { @@ -180,6 +180,7 @@ static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport, memcpy(&fl, &(*rp)->fl, sizeof(fl)); fl.fl_ip_sport = sport; fl.fl_ip_dport = dport; + fl.proto = protocol; ip_rt_put(*rp); *rp = NULL; return ip_route_output_flow(rp, &fl, sk, 0); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 00f983226672..dc0487b5bace 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -119,7 +119,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err != 0) goto failure; - err = ip_route_newports(&rt, inet->sport, inet->dport, sk); + err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport, + sk); if (err != 0) goto failure; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6ea353907af5..1ac35a65b2e5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -236,7 +236,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; - err = ip_route_newports(&rt, inet->sport, inet->dport, sk); + err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk); if (err) goto failure; -- cgit v1.2.3 From 3f4cfc2d11c9e29709e6f0f3add54039614d847a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 31 Jan 2006 17:44:07 -0800 Subject: [BRIDGE]: Fix device delete race. This is a simpler fix for the two races in bridge device removal. The Xen race of delif and notify is managed now by a new deleted flag. No need for barriers or other locking because of rtnl mutex. The del_timer_sync()'s are unnecessary, because br_stp_disable_port delete's the timers, and they will finish running before RCU callback. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 21 +++++++++++++++------ net/bridge/br_private.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ba442883e877..da687c8dc6ff 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p) { struct net_device *dev = p->dev; + dev->br_port = NULL; p->br = NULL; p->dev = NULL; dev_put(dev); @@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head) destroy_nbp(p); } -/* called with RTNL */ +/* Delete port(interface) from bridge is done in two steps. + * via RCU. First step, marks device as down. That deletes + * all the timers and stops new packets from flowing through. + * + * Final cleanup doesn't occur until after all CPU's finished + * processing packets. + * + * Protected from multiple admin operations by RTNL mutex + */ static void del_nbp(struct net_bridge_port *p) { struct net_bridge *br = p->br; struct net_device *dev = p->dev; - dev->br_port = NULL; + /* Race between RTNL notify and RCU callback */ + if (p->deleted) + return; + dev_set_promiscuity(dev, -1); cancel_delayed_work(&p->carrier_check); @@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p) spin_lock_bh(&br->lock); br_stp_disable_port(p); + p->deleted = 1; spin_unlock_bh(&br->lock); br_fdb_delete_by_port(br, p); list_del_rcu(&p->list); - del_timer_sync(&p->message_age_timer); - del_timer_sync(&p->forward_delay_timer); - del_timer_sync(&p->hold_timer); - call_rcu(&p->rcu, destroy_nbp_rcu); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c5bd631ffcd5..e330b17b6d81 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -68,6 +68,7 @@ struct net_bridge_port /* STP */ u8 priority; u8 state; + u8 deleted; u16 port_no; unsigned char topology_change_ack; unsigned char config_pending; -- cgit v1.2.3 From f9d9516db71eb3a8547948cdddc139eb1c1b9aee Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 31 Jan 2006 17:47:02 -0800 Subject: [NET]: Do not export inet_bind_bucket_create twice. inet_bind_bucket_create was exported twice. Keep the export in the file where inet_bind_bucket_create is defined. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1ac35a65b2e5..233bdf259965 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1845,7 +1845,6 @@ void __init tcp_v4_init(struct net_proto_family *ops) } EXPORT_SYMBOL(ipv4_specific); -EXPORT_SYMBOL(inet_bind_bucket_create); EXPORT_SYMBOL(tcp_hashinfo); EXPORT_SYMBOL(tcp_prot); EXPORT_SYMBOL(tcp_unhash); -- cgit v1.2.3 From 78b910429e2c037533d2a7bd9e95b4f94f905ef8 Mon Sep 17 00:00:00 2001 From: Eric W. Biederman Date: Tue, 31 Jan 2006 17:51:44 -0800 Subject: [IPV6] tcp_v6_send_synack: release the destination This patch fix dst reference counting in tcp_v6_send_synack Analysis: Currently tcp_v6_send_synack is never called with a dst entry so dst always comes in as NULL. ip6_dst_lookup calls ip6_route_output which calls dst_hold before it returns the dst entry. Neither xfrm_lookup nor tcp_make_synack consume the dst entry so we still have a dst_entry with a bumped refrence count at the end of this function. Therefore we need to call dst_release just before we return just like tcp_v4_send_synack does. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 66d04004afda..ca9cf6853755 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -515,6 +515,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, done: if (opt && opt != np->opt) sock_kfree_s(sk, opt, opt->tot_len); + dst_release(dst); return err; } -- cgit v1.2.3 From 0cbd782507c502428c8ab3e91bee3940c19ac4d4 Mon Sep 17 00:00:00 2001 From: David S. Miller Date: Tue, 31 Jan 2006 17:53:37 -0800 Subject: [DCCP] ipv6: dccp_v6_send_response() has a DST leak too. It was copy&pasted from tcp_v6_send_synack() which has a DST leak recently fixed by Eric W. Biederman. So dccp_v6_send_response() needs the same fix too. Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index df074259f9c3..80c4d048869e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -468,6 +468,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, done: if (opt && opt != np->opt) sock_kfree_s(sk, opt, opt->tot_len); + dst_release(dst); return err; } -- cgit v1.2.3 From 99acf0442111cc452ac1b93868dde8f6ff37a989 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Wed, 1 Feb 2006 03:06:56 -0800 Subject: [PATCH] DocBook: fix some kernel-doc comments in net/sunrpc Fix the syntax of some kernel-doc comments Signed-off-by: Martin Waitz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/sched.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 7415406aa1ae..802d4fe0f55c 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -908,10 +908,10 @@ void rpc_release_task(struct rpc_task *task) /** * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it - * @clnt - pointer to RPC client - * @flags - RPC flags - * @ops - RPC call ops - * @data - user call data + * @clnt: pointer to RPC client + * @flags: RPC flags + * @ops: RPC call ops + * @data: user call data */ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *ops, @@ -930,6 +930,7 @@ EXPORT_SYMBOL(rpc_run_task); /** * rpc_find_parent - find the parent of a child task. * @child: child task + * @parent: parent task * * Checks that the parent task is still sleeping on the * queue 'childq'. If so returns a pointer to the parent. -- cgit v1.2.3 From 8a3177604b729ec3b80e43790ee978863ac7551b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 1 Feb 2006 12:18:36 -0500 Subject: SUNRPC: Fix a lock recursion in the auth_gss downcall When we look up a new cred in the auth_gss downcall so that we can stuff the credcache, we do not want that lookup to queue up an upcall in order to initialise it. To do an upcall here not only redundant, but since we are already holding the inode->i_mutex, it will trigger a lock recursion. This patch allows rpcauth cache searches to indicate that they can cope with uninitialised credentials. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth.h | 5 +++++ net/sunrpc/auth.c | 17 ++++++++++------- net/sunrpc/auth_gss/auth_gss.c | 25 +++++++++++++++++++------ net/sunrpc/auth_unix.c | 6 +++--- 4 files changed, 37 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index b68c11a2d6dd..bfc5fb279539 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -50,6 +50,7 @@ struct rpc_cred { }; #define RPCAUTH_CRED_LOCKED 0x0001 #define RPCAUTH_CRED_UPTODATE 0x0002 +#define RPCAUTH_CRED_NEW 0x0004 #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 @@ -87,6 +88,10 @@ struct rpc_auth { * uid/gid, fs[ug]id, gids) */ +/* Flags for rpcauth_lookupcred() */ +#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ +#define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ + /* * Client authentication ops */ diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9ac1b8c26c01..1ca89c36da7a 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -184,7 +184,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) */ struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, - int taskflags) + int flags) { struct rpc_cred_cache *cache = auth->au_credcache; HLIST_HEAD(free); @@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, *cred = NULL; int nr = 0; - if (!(taskflags & RPC_TASK_ROOTCREDS)) + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) nr = acred->uid & RPC_CREDCACHE_MASK; retry: spin_lock(&rpc_credcache_lock); @@ -202,7 +202,7 @@ retry: hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { struct rpc_cred *entry; entry = hlist_entry(pos, struct rpc_cred, cr_hash); - if (entry->cr_ops->crmatch(acred, entry, taskflags)) { + if (entry->cr_ops->crmatch(acred, entry, flags)) { hlist_del(&entry->cr_hash); cred = entry; break; @@ -224,7 +224,7 @@ retry: rpcauth_destroy_credlist(&free); if (!cred) { - new = auth->au_ops->crcreate(auth, acred, taskflags); + new = auth->au_ops->crcreate(auth, acred, flags); if (!IS_ERR(new)) { #ifdef RPC_DEBUG new->cr_magic = RPCAUTH_CRED_MAGIC; @@ -238,7 +238,7 @@ retry: } struct rpc_cred * -rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) +rpcauth_lookupcred(struct rpc_auth *auth, int flags) { struct auth_cred acred = { .uid = current->fsuid, @@ -250,7 +250,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); get_group_info(acred.group_info); - ret = auth->au_ops->lookup_cred(auth, &acred, taskflags); + ret = auth->au_ops->lookup_cred(auth, &acred, flags); put_group_info(acred.group_info); return ret; } @@ -265,11 +265,14 @@ rpcauth_bindcred(struct rpc_task *task) .group_info = current->group_info, }; struct rpc_cred *ret; + int flags = 0; dprintk("RPC: %4d looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); get_group_info(acred.group_info); - ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); + if (task->tk_flags & RPC_TASK_ROOTCREDS) + flags |= RPCAUTH_LOOKUP_ROOTCREDS; + ret = auth->au_ops->lookup_cred(auth, &acred, flags); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 8d782282ec19..03affcbf6292 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -158,6 +158,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) old = gss_cred->gc_ctx; gss_cred->gc_ctx = ctx; cred->cr_flags |= RPCAUTH_CRED_UPTODATE; + cred->cr_flags &= ~RPCAUTH_CRED_NEW; write_unlock(&gss_ctx_lock); if (old) gss_put_ctx(old); @@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) } else { struct auth_cred acred = { .uid = uid }; spin_unlock(&gss_auth->lock); - cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); + cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); if (IS_ERR(cred)) { err = PTR_ERR(cred); goto err_put_ctx; @@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc) * Lookup RPCSEC_GSS cred for the current process */ static struct rpc_cred * -gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) +gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { - return rpcauth_lookup_credcache(auth, acred, taskflags); + return rpcauth_lookup_credcache(auth, acred, flags); } static struct rpc_cred * -gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) +gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); struct gss_cred *cred = NULL; @@ -785,13 +786,17 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) */ cred->gc_flags = 0; cred->gc_base.cr_ops = &gss_credops; + cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; cred->gc_service = gss_auth->service; + /* Is the caller prepared to initialise the credential? */ + if (flags & RPCAUTH_LOOKUP_NEW) + goto out; do { err = gss_create_upcall(gss_auth, cred); } while (err == -EAGAIN); if (err < 0) goto out_err; - +out: return &cred->gc_base; out_err: @@ -801,13 +806,21 @@ out_err: } static int -gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) +gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) { struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); + /* + * If the searchflags have set RPCAUTH_LOOKUP_NEW, then + * we don't really care if the credential has expired or not, + * since the caller should be prepared to reinitialise it. + */ + if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) + goto out; /* Don't match with creds that have expired. */ if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) return 0; +out: return (rc->cr_uid == acred->uid); } diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 1b3ed4fd1987..df14b6bfbf10 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -75,7 +75,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) atomic_set(&cred->uc_count, 1); cred->uc_flags = RPCAUTH_CRED_UPTODATE; - if (flags & RPC_TASK_ROOTCREDS) { + if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { cred->uc_uid = 0; cred->uc_gid = 0; cred->uc_gids[0] = NOGROUP; @@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred) * request root creds (e.g. for NFS swapping). */ static int -unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) +unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) { struct unx_cred *cred = (struct unx_cred *) rcred; int i; - if (!(taskflags & RPC_TASK_ROOTCREDS)) { + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { int groups; if (cred->uc_uid != acred->uid -- cgit v1.2.3 From 9842ef3557abf5ec2fd92bfa6e29ce0e271b3f6e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 1 Feb 2006 12:18:44 -0500 Subject: SUNRPC: rpc_timeout_upcall_queue should not sleep The function rpc_timeout_upcall_queue runs from a workqueue, and hence sleeping is not recommended. Convert the protection of the upcall queue from being mutex-based to being spinlock-based. Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 96 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9764c80ab0b2..7281746e6532 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -38,44 +38,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly; #define RPC_UPCALL_TIMEOUT (30*HZ) -static void -__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err) +static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, + void (*destroy_msg)(struct rpc_pipe_msg *), int err) { struct rpc_pipe_msg *msg; - void (*destroy_msg)(struct rpc_pipe_msg *); - destroy_msg = rpci->ops->destroy_msg; - while (!list_empty(head)) { + if (list_empty(head)) + return; + do { msg = list_entry(head->next, struct rpc_pipe_msg, list); - list_del_init(&msg->list); + list_del(&msg->list); msg->errno = err; destroy_msg(msg); - } -} - -static void -__rpc_purge_upcall(struct inode *inode, int err) -{ - struct rpc_inode *rpci = RPC_I(inode); - - __rpc_purge_list(rpci, &rpci->pipe, err); - rpci->pipelen = 0; + } while (!list_empty(head)); wake_up(&rpci->waitq); } static void rpc_timeout_upcall_queue(void *data) { + LIST_HEAD(free_list); struct rpc_inode *rpci = (struct rpc_inode *)data; struct inode *inode = &rpci->vfs_inode; + void (*destroy_msg)(struct rpc_pipe_msg *); - mutex_lock(&inode->i_mutex); - if (rpci->ops == NULL) - goto out; - if (rpci->nreaders == 0 && !list_empty(&rpci->pipe)) - __rpc_purge_upcall(inode, -ETIMEDOUT); -out: - mutex_unlock(&inode->i_mutex); + spin_lock(&inode->i_lock); + if (rpci->ops == NULL) { + spin_unlock(&inode->i_lock); + return; + } + destroy_msg = rpci->ops->destroy_msg; + if (rpci->nreaders == 0) { + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; + } + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); } int @@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) struct rpc_inode *rpci = RPC_I(inode); int res = -EPIPE; - mutex_lock(&inode->i_mutex); + spin_lock(&inode->i_lock); if (rpci->ops == NULL) goto out; if (rpci->nreaders) { @@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) res = 0; } out: - mutex_unlock(&inode->i_mutex); + spin_unlock(&inode->i_lock); wake_up(&rpci->waitq); return res; } @@ -115,21 +113,29 @@ static void rpc_close_pipes(struct inode *inode) { struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe_ops *ops; mutex_lock(&inode->i_mutex); - if (rpci->ops != NULL) { + ops = rpci->ops; + if (ops != NULL) { + LIST_HEAD(free_list); + + spin_lock(&inode->i_lock); rpci->nreaders = 0; - __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE); - __rpc_purge_upcall(inode, -EPIPE); - rpci->nwriters = 0; - if (rpci->ops->release_pipe) - rpci->ops->release_pipe(inode); + list_splice_init(&rpci->in_upcall, &free_list); + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; rpci->ops = NULL; + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); + rpci->nwriters = 0; + if (ops->release_pipe) + ops->release_pipe(inode); + cancel_delayed_work(&rpci->queue_timeout); + flush_scheduled_work(); } rpc_inode_setowner(inode, NULL); mutex_unlock(&inode->i_mutex); - cancel_delayed_work(&rpci->queue_timeout); - flush_scheduled_work(); } static struct inode * @@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp) goto out; msg = (struct rpc_pipe_msg *)filp->private_data; if (msg != NULL) { + spin_lock(&inode->i_lock); msg->errno = -EAGAIN; - list_del_init(&msg->list); + list_del(&msg->list); + spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } if (filp->f_mode & FMODE_WRITE) rpci->nwriters --; - if (filp->f_mode & FMODE_READ) + if (filp->f_mode & FMODE_READ) { rpci->nreaders --; - if (!rpci->nreaders) - __rpc_purge_upcall(inode, -EAGAIN); + if (rpci->nreaders == 0) { + LIST_HEAD(free_list); + spin_lock(&inode->i_lock); + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, + rpci->ops->destroy_msg, -EAGAIN); + } + } if (rpci->ops->release_pipe) rpci->ops->release_pipe(inode); out: @@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) } msg = filp->private_data; if (msg == NULL) { + spin_lock(&inode->i_lock); if (!list_empty(&rpci->pipe)) { msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, @@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) filp->private_data = msg; msg->copied = 0; } + spin_unlock(&inode->i_lock); if (msg == NULL) goto out_unlock; } @@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) res = rpci->ops->upcall(filp, msg, buf, len); if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; - list_del_init(&msg->list); + spin_lock(&inode->i_lock); + list_del(&msg->list); + spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } out_unlock: -- cgit v1.2.3 From adb12f63e0f837078c6832fa2c90649ddeaab54f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 1 Feb 2006 12:19:13 -0500 Subject: SUNRPC: Remove the deprecated function lookup_hash() from rpc_pipefs code Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7281746e6532..a5c0c7b6e151 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -630,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) return ERR_PTR(error); dir = nd->dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(nd); + dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len); if (IS_ERR(dentry)) goto out_err; if (dentry->d_inode) { @@ -692,7 +692,7 @@ rpc_rmdir(char *path) return error; dir = nd.dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(&nd); + dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out_release; @@ -753,7 +753,7 @@ rpc_unlink(char *path) return error; dir = nd.dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(&nd); + dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out_release; -- cgit v1.2.3 From fba3bad488a2eec2d76c067edb7a5ff92ef42431 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 1 Feb 2006 12:19:27 -0500 Subject: SUNRPC: Move upcall out of auth->au_ops->crcreate() This fixes a bug whereby if two processes try to look up the same auth_gss credential, they may end up creating two creds, and triggering two upcalls because the upcall is performed before the credential is added to the credcache. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth.h | 1 + net/sunrpc/auth.c | 8 ++++++++ net/sunrpc/auth_gss/auth_gss.c | 23 ++++++++++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index bfc5fb279539..2647798b72c7 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -110,6 +110,7 @@ struct rpc_authops { struct rpc_credops { const char * cr_name; /* Name of the auth flavour */ + int (*cr_init)(struct rpc_auth *, struct rpc_cred *); void (*crdestroy)(struct rpc_cred *); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 1ca89c36da7a..8d6f1a176b15 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -232,6 +232,14 @@ retry: goto retry; } else cred = new; + } else if ((cred->cr_flags & RPCAUTH_CRED_NEW) + && cred->cr_ops->cr_init != NULL + && !(flags & RPCAUTH_LOOKUP_NEW)) { + int res = cred->cr_ops->cr_init(auth, cred); + if (res < 0) { + put_rpccred(cred); + cred = ERR_PTR(res); + } } return (struct rpc_cred *) cred; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 03affcbf6292..bb46efd92e57 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -788,15 +788,6 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) cred->gc_base.cr_ops = &gss_credops; cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; cred->gc_service = gss_auth->service; - /* Is the caller prepared to initialise the credential? */ - if (flags & RPCAUTH_LOOKUP_NEW) - goto out; - do { - err = gss_create_upcall(gss_auth, cred); - } while (err == -EAGAIN); - if (err < 0) - goto out_err; -out: return &cred->gc_base; out_err: @@ -805,6 +796,19 @@ out_err: return ERR_PTR(err); } +static int +gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) +{ + struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); + struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base); + int err; + + do { + err = gss_create_upcall(gss_auth, gss_cred); + } while (err == -EAGAIN); + return err; +} + static int gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) { @@ -1254,6 +1258,7 @@ static struct rpc_authops authgss_ops = { static struct rpc_credops gss_credops = { .cr_name = "AUTH_GSS", .crdestroy = gss_destroy_cred, + .cr_init = gss_cred_init, .crmatch = gss_match, .crmarshal = gss_marshal, .crrefresh = gss_refresh, -- cgit v1.2.3 From 42c5e15f18d63c1ecf79d52bdaf4ea31cd22416d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 2 Feb 2006 16:53:26 -0800 Subject: [NET] snap: needs hardware checksum fix The SNAP code pops off it's 5 byte header, but doesn't adjust the checksum. This would cause problems when using device that does IP over SNAP and hardware receive checksums. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/802/psnap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/802/psnap.c b/net/802/psnap.c index 4d638944d933..34e42968b477 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -59,8 +59,10 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev, proto = find_snap_client(skb->h.raw); if (proto) { /* Pass the frame on. */ + u8 *hdr = skb->data; skb->h.raw += 5; skb_pull(skb, 5); + skb_postpull_rcsum(skb, hdr, 5); rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev); } else { skb->sk = NULL; -- cgit v1.2.3 From 4641e7a334adf6856300a98e7296dfc886c446af Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Feb 2006 16:55:45 -0800 Subject: [IPV6]: Don't hold extra ref count in ipv6_ifa_notify Currently the logic in ipv6_ifa_notify is to hold an extra reference count for addrconf dst's that get added to the routing table. Thus, when addrconf dst entries are taken out of the routing table, we need to drop that dst. However, addrconf dst entries may be removed from the routing table by means other than __ipv6_ifa_notify. So we're faced with the choice of either fixing up all places where addrconf dst entries are removed, or dropping the extra reference count altogether. I chose the latter because the ifp itself always holds a dst reference count of 1 while it's alive. This is dropped just before we kfree the ifp object. Therefore we know that in __ipv6_ifa_notify we will always hold that count. This bug was found by Eric W. Biederman. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d328d5986143..1db50487916b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3321,9 +3321,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) switch (event) { case RTM_NEWADDR: - dst_hold(&ifp->rt->u.dst); - if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL)) - dst_release(&ifp->rt->u.dst); + ip6_ins_rt(ifp->rt, NULL, NULL, NULL); if (ifp->idev->cnf.forwarding) addrconf_join_anycast(ifp); break; @@ -3334,8 +3332,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) dst_hold(&ifp->rt->u.dst); if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) dst_free(&ifp->rt->u.dst); - else - dst_release(&ifp->rt->u.dst); break; } } -- cgit v1.2.3 From 27852c26baab8b95fc9a2b3e8a18770ecd553f10 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 2 Feb 2006 16:57:31 -0800 Subject: [SCTP]: Fix 'fast retransmit' to send a TSN only once. SCTP used to "fast retransmit" a TSN every time we hit the number of missing reports for the TSN. However the Implementers Guide specifies that we should only "fast retransmit" a given TSN once. Subsequent retransmits should be timeouts only. Also change the number of missing reports to 3 as per the latest IG(similar to TCP). Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 2 +- net/sctp/output.c | 2 +- net/sctp/outqueue.c | 12 +++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 8c522ae031bb..072f407848a6 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -700,7 +700,7 @@ struct sctp_chunk { __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ __u8 pdiscard; /* Discard the whole packet now? */ __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ - __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __s8 fast_retransmit; /* Is this chunk fast retransmitted? */ __u8 tsn_missing_report; /* Data chunk missing counter. */ }; diff --git a/net/sctp/output.c b/net/sctp/output.c index a40991ef72c9..437cba7260a4 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -608,7 +608,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, * When a Fast Retransmit is being performed the sender SHOULD * ignore the value of cwnd and SHOULD NOT delay retransmission. */ - if (!chunk->fast_retransmit) + if (chunk->fast_retransmit <= 0) if (transport->flight_size >= transport->cwnd) { retval = SCTP_XMIT_RWND_FULL; goto finish; diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index efb72faba20c..f148f9576dd2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -406,7 +406,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, * chunks that are not yet acked should be added to the * retransmit queue. */ - if ((fast_retransmit && chunk->fast_retransmit) || + if ((fast_retransmit && (chunk->fast_retransmit > 0)) || (!fast_retransmit && !chunk->tsn_gap_acked)) { /* RFC 2960 6.2.1 Processing a Received SACK * @@ -603,7 +603,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, /* Mark the chunk as ineligible for fast retransmit * after it is retransmitted. */ - chunk->fast_retransmit = 0; + if (chunk->fast_retransmit > 0) + chunk->fast_retransmit = -1; *start_timer = 1; q->empty = 0; @@ -621,7 +622,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, list_for_each(lchunk1, lqueue) { chunk1 = list_entry(lchunk1, struct sctp_chunk, transmitted_list); - chunk1->fast_retransmit = 0; + if (chunk1->fast_retransmit > 0) + chunk1->fast_retransmit = -1; } } } @@ -1562,11 +1564,11 @@ static void sctp_mark_missing(struct sctp_outq *q, /* * M4) If any DATA chunk is found to have a * 'TSN.Missing.Report' - * value larger than or equal to 4, mark that chunk for + * value larger than or equal to 3, mark that chunk for * retransmission and start the fast retransmit procedure. */ - if (chunk->tsn_missing_report >= 4) { + if (chunk->tsn_missing_report >= 3) { chunk->fast_retransmit = 1; do_fast_retransmit = 1; } -- cgit v1.2.3 From f8addb3215bf58154f189017d934dfc06b62c75e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Feb 2006 16:59:16 -0800 Subject: [IPV4] multipath_wrandom: Fix softirq-unsafe spin lock usage The spin locks in multipath_wrandom may be obtained from either process context or softirq context depending on whether the packet is locally or remotely generated. Therefore we need to disable BH processing when taking these locks. This bug was found by Ingo's lock validator. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/multipath_wrandom.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c index d34a9fa608e0..342d0b9098f5 100644 --- a/net/ipv4/multipath_wrandom.c +++ b/net/ipv4/multipath_wrandom.c @@ -228,7 +228,7 @@ static void wrandom_set_nhinfo(__u32 network, struct multipath_dest *d, *target_dest = NULL; /* store the weight information for a certain route */ - spin_lock(&state[state_idx].lock); + spin_lock_bh(&state[state_idx].lock); /* find state entry for gateway or add one if necessary */ list_for_each_entry_rcu(r, &state[state_idx].head, list) { @@ -276,7 +276,7 @@ static void wrandom_set_nhinfo(__u32 network, * we are finished */ - spin_unlock(&state[state_idx].lock); + spin_unlock_bh(&state[state_idx].lock); } static void __multipath_free(struct rcu_head *head) @@ -302,7 +302,7 @@ static void wrandom_flush(void) for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) { struct multipath_route *r; - spin_lock(&state[i].lock); + spin_lock_bh(&state[i].lock); list_for_each_entry_rcu(r, &state[i].head, list) { struct multipath_dest *d; list_for_each_entry_rcu(d, &r->dests, list) { @@ -315,7 +315,7 @@ static void wrandom_flush(void) __multipath_free); } - spin_unlock(&state[i].lock); + spin_unlock_bh(&state[i].lock); } } -- cgit v1.2.3 From 6f4b6ec1cffcbb12cc47244381496d59b6a5a790 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Feb 2006 17:01:13 -0800 Subject: [IPV6]: Fix illegal dst locking in softirq context. On Tue, Jan 31, 2006 at 10:24:32PM +0100, Ingo Molnar wrote: > > [] _write_lock+0x8/0x10 > [] inet6_destroy_sock+0x25/0x100 > [] tcp_v6_destroy_sock+0x12/0x20 > [] inet_csk_destroy_sock+0x4a/0x150 > [] tcp_rcv_state_process+0xd4c/0xdd0 > [] tcp_v4_do_rcv+0xa9/0x340 > [] tcp_v4_rcv+0x8eb/0x9d0 OK this is definitely broken. We should never touch the dst lock in softirq context. Since inet6_destroy_sock may be called from that context due to the asynchronous nature of sockets, we can't take the lock there. In fact this sk_dst_reset is totally redundant since all IPv6 sockets use inet_sock_destruct as their socket destructor which always cleans up the dst anyway. So the solution is to simply remove the call. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 064ffab82a9f..6c9711ac1c03 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -369,12 +369,6 @@ int inet6_destroy_sock(struct sock *sk) struct sk_buff *skb; struct ipv6_txoptions *opt; - /* - * Release destination entry - */ - - sk_dst_reset(sk); - /* Release rx options */ if ((skb = xchg(&np->pktoptions, NULL)) != NULL) -- cgit v1.2.3 From f00c401b9b5f0a90e2eb05705f5988fbda0b082b Mon Sep 17 00:00:00 2001 From: Horms Date: Thu, 2 Feb 2006 17:03:18 -0800 Subject: [IPV4]: Remove suprious use of goto out: in icmp_reply This seems to be an artifact of the follwoing commit in February '02. e7e173af42dbf37b1d946f9ee00219cb3b2bea6a In a nutshell, goto out and return actually do the same thing, and both are called in this function. This patch removes out. Signed-Off-By: Horms Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 105039eb7629..6bc0887b0834 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -385,7 +385,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) u32 daddr; if (ip_options_echo(&icmp_param->replyopts, skb)) - goto out; + return; if (icmp_xmit_lock()) return; @@ -416,7 +416,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) ip_rt_put(rt); out_unlock: icmp_xmit_unlock(); -out:; } -- cgit v1.2.3 From 0dec456d1fe73e0539625f0973ee8ef8fb805943 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 2 Feb 2006 20:40:09 -0800 Subject: [NET]: Add CONFIG_NETDEBUG to suppress bad packet messages. If you are on a hostile network, or are running protocol tests, you can easily get the logged swamped by messages about bad UDP and ICMP packets. This turns those messages off unless a config option is enabled. Signed-off-by: Stephen Hemminger Acked-by: Dave Jones Signed-off-by: David S. Miller --- include/net/sock.h | 8 ++++---- net/Kconfig | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 1806e5b61419..30758035d616 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1354,12 +1354,12 @@ extern int sock_get_timestamp(struct sock *, struct timeval __user *); * Enable debug/info messages */ -#if 0 -#define NETDEBUG(fmt, args...) do { } while (0) -#define LIMIT_NETDEBUG(fmt, args...) do { } while(0) -#else +#ifdef CONFIG_NETDEBUG #define NETDEBUG(fmt, args...) printk(fmt,##args) #define LIMIT_NETDEBUG(fmt, args...) do { if (net_ratelimit()) printk(fmt,##args); } while(0) +#else +#define NETDEBUG(fmt, args...) do { } while (0) +#define LIMIT_NETDEBUG(fmt, args...) do { } while(0) #endif /* diff --git a/net/Kconfig b/net/Kconfig index bc603d9aea56..5126f58d9c44 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -27,6 +27,13 @@ if NET menu "Networking options" +config NETDEBUG + bool "Network packet debugging" + help + You can say Y here if you want to get additional messages useful in + debugging bad packets, but can overwhelm logs under denial of service + attacks. + source "net/packet/Kconfig" source "net/unix/Kconfig" source "net/xfrm/Kconfig" -- cgit v1.2.3