From 8e54588161577435d64dfb5cfdf40a73a5705ea0 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Tue, 28 Aug 2007 14:34:43 -0700 Subject: [PATCH 01/20] [BNX2]: Use msleep(). bnx2.c (incorrectly) sets current->state directly to TASK_UNINTERRUPTIBLE, without going through set_task_state(). However all the code wants to do is an msleep so just make it do that instead... Signed-off-by: Arjan van de Ven Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 24e7f9ab3f5a..00918602ba88 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3935,10 +3935,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val); if ((CHIP_ID(bp) == CHIP_ID_5706_A0) || - (CHIP_ID(bp) == CHIP_ID_5706_A1)) { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ / 50); - } + (CHIP_ID(bp) == CHIP_ID_5706_A1)) + msleep(20); /* Reset takes approximate 30 usec */ for (i = 0; i < 10; i++) { From 594a9dfae7113d9601b2c353754c40d0b7e00a03 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 28 Aug 2007 15:39:42 -0700 Subject: [PATCH 02/20] [BNX2]: Add write posting comment. Add comment to explain why we cannot read back after chip reset before delaying. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 00918602ba88..854d80c330ec 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3934,6 +3934,10 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) /* Chip reset. */ REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val); + /* Reading back any register after chip reset will hang the + * bus on 5706 A0 and A1. The msleep below provides plenty + * of margin for write posting. + */ if ((CHIP_ID(bp) == CHIP_ID_5706_A0) || (CHIP_ID(bp) == CHIP_ID_5706_A1)) msleep(20); From 378be2c08314fc46e3f814fa264ff8ebdb79712f Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Tue, 28 Aug 2007 15:43:14 -0700 Subject: [PATCH 03/20] [PKTGEN]: Fix multiqueue oops. Initially pkt_dev can be NULL this causes netif_subqueue_stopped to oops. The patch below should cure it. But maybe the pktgen TX logic should be reworked to better support the new multiqueue support. Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- net/core/pktgen.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 7bae576ac115..4ad62d375373 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3331,8 +3331,9 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) } if ((netif_queue_stopped(odev) || - netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) || - need_resched()) { + (pkt_dev->skb && + netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) || + need_resched()) { idle_start = getCurUs(); if (!netif_running(odev)) { From ea2dfb3733d53ac98b17756435d1f99e25490357 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 13 Jul 2007 17:01:19 -0400 Subject: [PATCH 04/20] SCTP: properly clean up fragment and ordering queues during FWD-TSN. When we recieve a FWD-TSN (meaning the peer has abandoned the data), we need to clean up any partially received messages that may be hanging out on the re-assembly or re-ordering queues. This is a MUST requirement that was not properly done before. Signed-off-by: Vlad Yasevich --- include/net/sctp/ulpqueue.h | 1 + net/sctp/sm_sideeffect.c | 3 ++ net/sctp/ulpqueue.c | 75 ++++++++++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h index 39ea3f442b47..cd33270e86dd 100644 --- a/include/net/sctp/ulpqueue.h +++ b/include/net/sctp/ulpqueue.h @@ -83,6 +83,7 @@ int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc); /* Skip over an SSN. */ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn); +void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *, __u32); #endif /* __sctp_ulpqueue_h__ */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index d9fad4f6ffc3..1907318e70f1 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1130,6 +1130,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, /* Move the Cumulattive TSN Ack ahead. */ sctp_tsnmap_skip(&asoc->peer.tsn_map, cmd->obj.u32); + /* purge the fragmentation queue */ + sctp_ulpq_reasm_flushtsn(&asoc->ulpq, cmd->obj.u32); + /* Abort any in progress partial delivery. */ sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); break; diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 34eb977a204d..fa0ba2a5564e 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -659,6 +659,46 @@ done: return retval; } +/* + * Flush out stale fragments from the reassembly queue when processing + * a Forward TSN. + * + * RFC 3758, Section 3.6 + * + * After receiving and processing a FORWARD TSN, the data receiver MUST + * take cautions in updating its re-assembly queue. The receiver MUST + * remove any partially reassembled message, which is still missing one + * or more TSNs earlier than or equal to the new cumulative TSN point. + * In the event that the receiver has invoked the partial delivery API, + * a notification SHOULD also be generated to inform the upper layer API + * that the message being partially delivered will NOT be completed. + */ +void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn) +{ + struct sk_buff *pos, *tmp; + struct sctp_ulpevent *event; + __u32 tsn; + + if (skb_queue_empty(&ulpq->reasm)) + return; + + skb_queue_walk_safe(&ulpq->reasm, pos, tmp) { + event = sctp_skb2event(pos); + tsn = event->tsn; + + /* Since the entire message must be abandoned by the + * sender (item A3 in Section 3.5, RFC 3758), we can + * free all fragments on the list that are less then + * or equal to ctsn_point + */ + if (TSN_lte(tsn, fwd_tsn)) { + __skb_unlink(pos, &ulpq->reasm); + sctp_ulpevent_free(event); + } else + break; + } +} + /* Helper function to gather skbs that have possibly become * ordered by an an incoming chunk. */ @@ -794,7 +834,7 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, /* Helper function to gather skbs that have possibly become * ordered by forward tsn skipping their dependencies. */ -static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq) +static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) { struct sk_buff *pos, *tmp; struct sctp_ulpevent *cevent; @@ -813,31 +853,40 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq) csid = cevent->stream; cssn = cevent->ssn; - if (cssn != sctp_ssn_peek(in, csid)) + /* Have we gone too far? */ + if (csid > sid) break; - /* Found it, so mark in the ssnmap. */ - sctp_ssn_next(in, csid); + /* Have we not gone far enough? */ + if (csid < sid) + continue; + + /* see if this ssn has been marked by skipping */ + if (!SSN_lt(cssn, sctp_ssn_peek(in, csid))) + break; __skb_unlink(pos, &ulpq->lobby); - if (!event) { + if (!event) /* Create a temporary list to collect chunks on. */ event = sctp_skb2event(pos); - __skb_queue_tail(&temp, sctp_event2skb(event)); - } else { - /* Attach all gathered skbs to the event. */ - __skb_queue_tail(&temp, pos); - } + + /* Attach all gathered skbs to the event. */ + __skb_queue_tail(&temp, pos); } /* Send event to the ULP. 'event' is the sctp_ulpevent for * very first SKB on the 'temp' list. */ - if (event) + if (event) { + /* see if we have more ordered that we can deliver */ + sctp_ulpq_retrieve_ordered(ulpq, event); sctp_ulpq_tail_event(ulpq, event); + } } -/* Skip over an SSN. */ +/* Skip over an SSN. This is used during the processing of + * Forwared TSN chunk to skip over the abandoned ordered data + */ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) { struct sctp_stream *in; @@ -855,7 +904,7 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) /* Go find any other chunks that were waiting for * ordering and deliver them if needed. */ - sctp_ulpq_reap_ordered(ulpq); + sctp_ulpq_reap_ordered(ulpq, sid); return; } From ab3e5e7b65dde661f5eb86b445496c5967283333 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 2 Aug 2007 16:51:42 -0400 Subject: [PATCH 05/20] SCTP: Assign stream sequence numbers to the entire message Currently we only assign the sequence number to a packet that we are about to transmit. This however breaks the Partial Reliability extensions, because it's possible for us to never transmit a packet, i.e. it expires before we get to send it. In such cases, if the message contained multiple SCTP fragments, and we did manage to send the first part of the message, the Stream sequence numbers would get into invalid state and cause receiver to stall. Signed-off-by: Vlad Yasevich --- net/sctp/sm_make_chunk.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 51c4d7fef1d2..2b1129a7a94a 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1174,25 +1174,36 @@ out: */ void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) { + struct sctp_datamsg *msg; + struct sctp_chunk *lchunk; + struct sctp_stream *stream; __u16 ssn; __u16 sid; if (chunk->has_ssn) return; - /* This is the last possible instant to assign a SSN. */ - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { - ssn = 0; - } else { - sid = ntohs(chunk->subh.data_hdr->stream); - if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) - ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid); - else - ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid); - } + /* All fragments will be on the same stream */ + sid = ntohs(chunk->subh.data_hdr->stream); + stream = &chunk->asoc->ssnmap->out; - chunk->subh.data_hdr->ssn = htons(ssn); - chunk->has_ssn = 1; + /* Now assign the sequence number to the entire message. + * All fragments must have the same stream sequence number. + */ + msg = chunk->msg; + list_for_each_entry(lchunk, &msg->chunks, frag_list) { + if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { + ssn = 0; + } else { + if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) + ssn = sctp_ssn_next(stream, sid); + else + ssn = sctp_ssn_peek(stream, sid); + } + + lchunk->subh.data_hdr->ssn = htons(ssn); + lchunk->has_ssn = 1; + } } /* Helper function to assign a TSN if needed. This assumes that both From 8d614ade511fef11f992d6a73e538d33b3b81f12 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 6 Aug 2007 13:55:47 +0800 Subject: [PATCH 06/20] SCTP: Fix sctp_addto_chunk() to add pad with correct length At function sctp_addto_chunk(), it do pad before add payload to chunk if chunk length is not 4-byte alignment. But it do pad with a bad length. This patch fixed this probleam. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- net/sctp/sm_make_chunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 2b1129a7a94a..93df833f34f4 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1128,7 +1128,7 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) void *target; void *padding; int chunklen = ntohs(chunk->chunk_hdr->length); - int padlen = chunklen % 4; + int padlen = WORD_ROUND(chunklen) - chunklen; padding = skb_put(chunk->skb, padlen); target = skb_put(chunk->skb, len); From 00f1c2df2a1c4903f4daa1333bafeb6dcbc9591d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 21 Aug 2007 15:50:01 +0800 Subject: [PATCH 07/20] SCTP: Fix to encode PROTOCOL VIOLATION error cause correctly PROTOCOL VIOLATION error cause in ABORT is bad encode when make abort chunk. When SCTP encode ABORT chunk with PROTOCOL VIOLATION error cause, it just add the error messages to PROTOCOL VIOLATION error cause, the rest four bytes(struct sctp_paramhdr) is just add to the chunk, not change the length of error cause. This cause the ABORT chunk to be a bad format. The chunk is like this: ABORT chunk Chunk type: ABORT (6) Chunk flags: 0x00 Chunk length: 72 (*1) Protocol violation cause Cause code: Protocol violation (0x000d) Cause length: 62 (*2) Cause information: 5468652063756D756C61746976652074736E2061636B2062... Cause padding: 0000 [Needless] 00030010 Chunk Length(*1) = 72 but Cause length(*2) only 62, not include the extend 4 bytes. ((72 - sizeof(chunk_hdr)) = 68) != (62 +3) / 4 * 4 Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- include/net/sctp/sm.h | 2 +- include/net/sctp/structs.h | 1 + net/sctp/sm_make_chunk.c | 73 +++++++++++++++++++++++++++----------- net/sctp/sm_statefuns.c | 4 +-- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 73cb9943c8a8..991c85bb9e36 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -214,7 +214,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, const struct sctp_chunk *); struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, const struct sctp_chunk *); -void sctp_init_cause(struct sctp_chunk *, __be16 cause, const void *, size_t); +void sctp_init_cause(struct sctp_chunk *, __be16 cause, size_t); struct sctp_chunk *sctp_make_abort(const struct sctp_association *, const struct sctp_chunk *, const size_t hint); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ee4559b11302..c0d5848c33dc 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -726,6 +726,7 @@ int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, struct iovec *data); void sctp_chunk_free(struct sctp_chunk *); void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); +void *sctp_addto_param(struct sctp_chunk *, int len, const void *data); struct sctp_chunk *sctp_chunkify(struct sk_buff *, const struct sctp_association *, struct sock *); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 93df833f34f4..adc5e5934728 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -110,7 +110,7 @@ static const struct sctp_paramhdr prsctp_param = { * abort chunk. */ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, - const void *payload, size_t paylen) + size_t paylen) { sctp_errhdr_t err; __u16 len; @@ -120,7 +120,6 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, len = sizeof(sctp_errhdr_t) + paylen; err.length = htons(len); chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); - sctp_addto_chunk(chunk, paylen, payload); } /* 3.3.2 Initiation (INIT) (1) @@ -780,8 +779,8 @@ struct sctp_chunk *sctp_make_abort_no_data( /* Put the tsn back into network byte order. */ payload = htonl(tsn); - sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, - sizeof(payload)); + sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload)); + sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints * @@ -823,7 +822,8 @@ struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, goto err_copy; } - sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen); + sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen); + sctp_addto_chunk(retval, paylen, payload); if (paylen) kfree(payload); @@ -850,15 +850,17 @@ struct sctp_chunk *sctp_make_abort_violation( struct sctp_paramhdr phdr; retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen - + sizeof(sctp_chunkhdr_t)); + + sizeof(sctp_paramhdr_t)); if (!retval) goto end; - sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen); + sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen + + sizeof(sctp_paramhdr_t)); phdr.type = htons(chunk->chunk_hdr->type); phdr.length = chunk->chunk_hdr->length; - sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr); + sctp_addto_chunk(retval, paylen, payload); + sctp_addto_param(retval, sizeof(sctp_paramhdr_t), &phdr); end: return retval; @@ -955,7 +957,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, if (!retval) goto nodata; - sctp_init_cause(retval, cause_code, payload, paylen); + sctp_init_cause(retval, cause_code, paylen); + sctp_addto_chunk(retval, paylen, payload); nodata: return retval; @@ -1143,6 +1146,25 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) return target; } +/* Append bytes to the end of a parameter. Will panic if chunk is not big + * enough. + */ +void *sctp_addto_param(struct sctp_chunk *chunk, int len, const void *data) +{ + void *target; + int chunklen = ntohs(chunk->chunk_hdr->length); + + target = skb_put(chunk->skb, len); + + memcpy(target, data, len); + + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = htons(chunklen + len); + chunk->chunk_end = skb_tail_pointer(chunk->skb); + + return target; +} + /* Append bytes from user space to the end of a chunk. Will panic if * chunk is not big enough. * Returns a kernel err value. @@ -1477,7 +1499,8 @@ no_hmac: __be32 n = htonl(usecs); sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, - &n, sizeof(n)); + sizeof(n)); + sctp_addto_chunk(*errp, sizeof(n), &n); *error = -SCTP_IERROR_STALE_COOKIE; } else *error = -SCTP_IERROR_NOMEM; @@ -1567,7 +1590,8 @@ static int sctp_process_missing_param(const struct sctp_association *asoc, report.num_missing = htonl(1); report.type = paramtype; sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM, - &report, sizeof(report)); + sizeof(report)); + sctp_addto_chunk(*errp, sizeof(report), &report); } /* Stop processing this chunk. */ @@ -1585,7 +1609,7 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc, *errp = sctp_make_op_error_space(asoc, chunk, 0); if (*errp) - sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0); /* Stop processing this chunk. */ return 0; @@ -1606,9 +1630,10 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, *errp = sctp_make_op_error_space(asoc, chunk, payload_len); if (*errp) { - sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error, - sizeof(error)); - sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param); + sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, + sizeof(error) + sizeof(sctp_paramhdr_t)); + sctp_addto_chunk(*errp, sizeof(error), error); + sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param); } return 0; @@ -1629,9 +1654,10 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, if (!*errp) *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*errp) - sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, - param.v, len); + if (*errp) { + sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); + sctp_addto_chunk(*errp, len, param.v); + } /* Stop processing this chunk. */ return 0; @@ -1683,10 +1709,13 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*errp) + if (*errp) { sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, - param.v, WORD_ROUND(ntohs(param.p->length))); + sctp_addto_chunk(*errp, + WORD_ROUND(ntohs(param.p->length)), + param.v); + } break; case SCTP_PARAM_ACTION_SKIP: @@ -1701,8 +1730,10 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, if (*errp) { sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, - param.v, WORD_ROUND(ntohs(param.p->length))); + sctp_addto_chunk(*errp, + WORD_ROUND(ntohs(param.p->length)), + param.v); } else { /* If there is no memory for generating the ERROR * report as specified, an ABORT will be triggered diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 71cad56dd73f..350d47654720 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3362,7 +3362,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, abort = sctp_make_abort(asoc, asconf_ack, sizeof(sctp_errhdr_t)); if (abort) { - sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0); + sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, 0); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); } @@ -3392,7 +3392,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, abort = sctp_make_abort(asoc, asconf_ack, sizeof(sctp_errhdr_t)); if (abort) { - sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0); + sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); } From d99fa42963a5ae394cf1df9d5bb739eb378a189b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 27 Aug 2007 11:19:24 +0800 Subject: [PATCH 08/20] SCTP: Use net_ratelimit to suppress error messages print too fast When multi bundling SHUTDOWN-ACK message is received in ESTAB state, this will cause "sctp protocol violation state" message print many times. If SHUTDOWN-ACK is bundled 300 times in one packet, message will be print 300 times. The same problem also exists when received unexpected HEARTBEAT-ACK message which is bundled message times. This patch used net_ratelimit() to suppress error messages print too fast. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- net/sctp/sm_sideeffect.c | 5 +++-- net/sctp/sm_statefuns.c | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1907318e70f1..8d7890083493 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1013,8 +1013,9 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, break; case SCTP_DISPOSITION_VIOLATION: - printk(KERN_ERR "sctp protocol violation state %d " - "chunkid %d\n", state, subtype.chunk); + if (net_ratelimit()) + printk(KERN_ERR "sctp protocol violation state %d " + "chunkid %d\n", state, subtype.chunk); break; case SCTP_DISPOSITION_NOT_IMPL: diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 350d47654720..276e26d3d7da 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1032,19 +1032,21 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, /* This should never happen, but lets log it if so. */ if (unlikely(!link)) { if (from_addr.sa.sa_family == AF_INET6) { - printk(KERN_WARNING - "%s association %p could not find address " - NIP6_FMT "\n", - __FUNCTION__, - asoc, - NIP6(from_addr.v6.sin6_addr)); + if (net_ratelimit()) + printk(KERN_WARNING + "%s association %p could not find address " + NIP6_FMT "\n", + __FUNCTION__, + asoc, + NIP6(from_addr.v6.sin6_addr)); } else { - printk(KERN_WARNING - "%s association %p could not find address " - NIPQUAD_FMT "\n", - __FUNCTION__, - asoc, - NIPQUAD(from_addr.v4.sin_addr.s_addr)); + if (net_ratelimit()) + printk(KERN_WARNING + "%s association %p could not find address " + NIPQUAD_FMT "\n", + __FUNCTION__, + asoc, + NIPQUAD(from_addr.v4.sin_addr.s_addr)); } return SCTP_DISPOSITION_DISCARD; } From 2772b495efe341a02c867bc3a03d7362bd336832 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 21 Aug 2007 14:24:30 +0900 Subject: [PATCH 09/20] SCTP: Pick the correct port when binding to 0. sctp_bindx() allows the use of unspecified port. The problem is that every address we bind to ends up selecting a new port if the user specified port 0. This patch allows re-use of the already selected port when the port from bindx was 0. Signed-off-by: Vlad Yasevich --- net/sctp/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 01c6364245b7..de7921226725 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -353,6 +353,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) * The function sctp_get_port_local() does duplicate address * detection. */ + addr->v4.sin_port = htons(snum); if ((ret = sctp_get_port_local(sk, addr))) { if (ret == (long) sk) { /* This endpoint has a conflicting address. */ From cc75689a4c4eb94b2fd7e3870347b9237ab39503 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 24 Aug 2007 19:30:25 +0900 Subject: [PATCH 10/20] SCTP: Uncomfirmed transports can't become Inactive Do not set Unconfirmed transports to Inactive state. This may result in an inactive association being destroyed since we start counting errors on "inactive" transports against the association. This was found at the SCTP interop event. Signed-off-by: Vlad Yasevich --- net/sctp/associola.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 498edb0cd4e5..2ad1caf1ea42 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -727,7 +727,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, break; case SCTP_TRANSPORT_DOWN: - transport->state = SCTP_INACTIVE; + /* if the transort was never confirmed, do not transition it + * to inactive state. + */ + if (transport->state != SCTP_UNCONFIRMED) + transport->state = SCTP_INACTIVE; + spc_state = SCTP_ADDR_UNREACHABLE; break; From d0ce92910bc04e107b2f3f2048f07e94f570035d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 24 Aug 2007 19:37:46 +0900 Subject: [PATCH 11/20] SCTP: Do not retransmit chunks that are newer then rtt. When performing a retransmit, do not include the chunk if it was sent less then 1 rtt ago. The reason is that we may receive the SACK very soon and wouldn't retransmit. Suggested by Randy Stewart. Signed-off-by: Vlad Yasevich --- net/sctp/outqueue.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 992f361084b7..28f4fe77ceee 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -421,6 +421,13 @@ void sctp_retransmit_mark(struct sctp_outq *q, */ if ((fast_retransmit && (chunk->fast_retransmit > 0)) || (!fast_retransmit && !chunk->tsn_gap_acked)) { + /* If this chunk was sent less then 1 rto ago, do not + * retransmit this chunk, but give the peer time + * to acknowlege it. + */ + if ((jiffies - chunk->sent_at) < transport->rto) + continue; + /* RFC 2960 6.2.1 Processing a Received SACK * * C) Any time a DATA chunk is marked for From 498d63071ef378e201979e441aefcc6565702ca7 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 30 Aug 2007 14:03:58 -0400 Subject: [PATCH 12/20] SCTP: Correctly disable listening when backlog is 0. Signed-off-by: Vlad Yasevich --- net/sctp/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index de7921226725..33354602ae86 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5203,6 +5203,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) sctp_unhash_endpoint(ep); sk->sk_state = SCTP_SS_CLOSED; + return 0; } /* Return if we are already listening. */ @@ -5250,6 +5251,7 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) sctp_unhash_endpoint(ep); sk->sk_state = SCTP_SS_CLOSED; + return 0; } if (sctp_sstate(sk, LISTENING)) From 609ee4679b8a0831257552dd2b0e54f509ba0c77 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 31 Aug 2007 03:10:59 +0900 Subject: [PATCH 13/20] SCTP: Abort on COOKIE-ECHO if backlog is exceeded. Currently we abort on the INIT chunk we our backlog is currenlty exceeded. Delay this about untill COOKIE-ECHO to give the user time to accept the socket. Also, make sure that we treat sk_max_backlog of 0 as no connections allowed. Signed-off-by: Vlad Yasevich --- net/sctp/sm_statefuns.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 276e26d3d7da..177528ed3e1b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -264,7 +264,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; - struct sock *sk; int len; /* 6.10 Bundling @@ -285,16 +284,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); - sk = ep->base.sk; - /* If the endpoint is not listening or if the number of associations - * on the TCP-style socket exceed the max backlog, respond with an - * ABORT. - */ - if (!sctp_sstate(sk, LISTENING) || - (sctp_style(sk, TCP) && - sk_acceptq_is_full(sk))) - return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); - /* 3.1 A packet containing an INIT chunk MUST have a zero Verification * Tag. */ @@ -590,6 +579,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, struct sctp_ulpevent *ev, *ai_ev = NULL; int error = 0; struct sctp_chunk *err_chk_p; + struct sock *sk; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. @@ -605,6 +595,15 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* If the endpoint is not listening or if the number of associations + * on the TCP-style socket exceed the max backlog, respond with an + * ABORT. + */ + sk = ep->base.sk; + if (!sctp_sstate(sk, LISTENING) || + (sctp_style(sk, TCP) && sk_acceptq_is_full(sk))) + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); + /* "Decode" the chunk. We have no optional parameters so we * are in good shape. */ From cb243a1a9fef4aaff262a5dd14f987070d37229b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 6 Aug 2007 13:55:58 +0800 Subject: [PATCH 14/20] SCTP: Fix to handle invalid parameter length correctly If an INIT with invalid parameter length look like this: Parameter Type : 1 Parameter Length: 800 and not contain any payload, SCTP will ignore this parameter and send back a INIT-ACK. This patch is fix to handle this invalid parameter length correctly. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- net/sctp/sm_make_chunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index adc5e5934728..79856c924525 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1833,7 +1833,7 @@ int sctp_verify_init(const struct sctp_association *asoc, * VIOLATION error. We build the ERROR chunk here and let the normal * error handling code build and send the packet. */ - if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) { + if (param.v != (void*)chunk->chunk_end) { sctp_process_inv_paramlength(asoc, param.p, chunk, errp); return 0; } From 05bb1fad1cde025a864a90cfeb98dcbefe78a44a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 30 Aug 2007 22:10:28 -0700 Subject: [PATCH 15/20] [TCP]: Allow minimum RTO to be configurable via routing metrics. Cell phone networks do link layer retransmissions and other things that cause unnecessary timeout retransmits. So allow the minimum RTO to be inflated per-route to deal with this. Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 ++ net/ipv4/tcp_input.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index c91476ce314a..dff3192374f8 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -351,6 +351,8 @@ enum #define RTAX_INITCWND RTAX_INITCWND RTAX_FEATURES, #define RTAX_FEATURES RTAX_FEATURES + RTAX_RTO_MIN, +#define RTAX_RTO_MIN RTAX_RTO_MIN __RTAX_MAX }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9785df37a65f..1ee72127462b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -555,6 +555,16 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) tcp_grow_window(sk, skb); } +static u32 tcp_rto_min(struct sock *sk) +{ + struct dst_entry *dst = __sk_dst_get(sk); + u32 rto_min = TCP_RTO_MIN; + + if (dst_metric_locked(dst, RTAX_RTO_MIN)) + rto_min = dst->metrics[RTAX_RTO_MIN-1]; + return rto_min; +} + /* Called to compute a smoothed rtt estimate. The data fed to this * routine either comes from timestamps, or from segments that were * known _not_ to have been retransmitted [see Karn/Partridge @@ -616,13 +626,13 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt) if (tp->mdev_max < tp->rttvar) tp->rttvar -= (tp->rttvar-tp->mdev_max)>>2; tp->rtt_seq = tp->snd_nxt; - tp->mdev_max = TCP_RTO_MIN; + tp->mdev_max = tcp_rto_min(sk); } } else { /* no previous measure. */ tp->srtt = m<<3; /* take the measured time to be rtt */ tp->mdev = m<<1; /* make sure rto = 3*rtt */ - tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN); + tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); tp->rtt_seq = tp->snd_nxt; } } From df1c0b8468b34628ed12b103804a4576cd9af8bb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 30 Aug 2007 22:15:35 -0700 Subject: [PATCH 16/20] [BRIDGE]: Packets leaking out of disabled/blocked ports. This patch fixes some packet leakage in bridge. The bridging code was allowing forward table entries to be generated even if a device was being blocked. The fix is to not add forwarding database entries unless the port is active. The bug arose as part of the conversion to processing STP frames through normal receive path (in 2.6.17). Signed-off-by: Stephen Hemminger Acked-by: John W. Linville Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 5 +++++ net/bridge/br_input.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 69b70977f000..eb57502bb264 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -384,6 +384,11 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, if (hold_time(br) == 0) return; + /* ignore packets unless we are using this port */ + if (!(source->state == BR_STATE_LEARNING || + source->state == BR_STATE_FORWARDING)) + return; + fdb = fdb_find(head, addr); if (likely(fdb)) { /* attempt to update an entry for a local interface */ diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 5c18595b7616..6f468fc3357a 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -101,9 +101,8 @@ static int br_handle_local_finish(struct sk_buff *skb) { struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); - if (p && p->state != BR_STATE_DISABLED) + if (p) br_fdb_update(p->br, p, eth_hdr(skb)->h_source); - return 0; /* process further */ } From b4a488d1824a2cc3514f9ee1298d805bd5edc893 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 30 Aug 2007 22:16:22 -0700 Subject: [PATCH 17/20] [BRIDGE]: Fix OOPS when bridging device without ethtool. Bridge code calls ethtool to get speed. The conversion to using only ethtool_ops broke the case of devices without ethtool_ops. This is a new regression in 2.6.23. Rearranged the switch to a logical order, and use gcc initializer. Ps: speed should have been part of the network device structure from the start rather than burying it in ethtool. Signed-off-by: Stephen Hemminger Acked-by: Matthew Wilcox Signed-off-by: David S. Miller --- net/bridge/br_if.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 749f0e8f541d..9272f12f664c 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -33,17 +33,17 @@ */ static int port_cost(struct net_device *dev) { - if (dev->ethtool_ops->get_settings) { - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - int err = dev->ethtool_ops->get_settings(dev, &ecmd); - if (!err) { + if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; + + if (!dev->ethtool_ops->get_settings(dev, &ecmd)) { switch(ecmd.speed) { - case SPEED_100: - return 19; - case SPEED_1000: - return 4; case SPEED_10000: return 2; + case SPEED_1000: + return 4; + case SPEED_100: + return 19; case SPEED_10: return 100; } From dbaaa07a60edf71670b484a65e14400ab40c84f7 Mon Sep 17 00:00:00 2001 From: Lucas Nussbaum Date: Thu, 30 Aug 2007 22:35:46 -0700 Subject: [PATCH 18/20] [NET_SCHED] sch_prio.c: remove duplicate call of tc_classify() When CONFIG_NET_CLS_ACT is enabled, tc_classify() is called twice in prio_classify(). This causes "interesting" behaviour: with the setup below, packets are duplicated, sent twice to ifb0, and then loop in and out of ifb0. The patch uses the previously calculated return value in the switch, which is probably what Patrick had in mind in commit bdba91ec70fb5ccbdeb1c7068319adc6ea9e1a7d -- maybe Patrick can double-check this? -- example setup -- ifconfig ifb0 up tc qdisc add dev ifb0 root netem delay 2s tc qdisc add dev $ETH root handle 1: prio tc filter add dev $ETH parent 1: protocol ip prio 10 u32 \ match ip dst 172.24.110.6/32 flowid 1:1 \ action mirred egress redirect dev ifb0 ping -c1 172.24.110.6 Signed-off-by: Lucas Nussbaum Signed-off-by: David S. Miller --- net/sched/sch_prio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 4a49db65772e..abd82fc3ec60 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -44,7 +44,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) if (TC_H_MAJ(skb->priority) != sch->handle) { err = tc_classify(skb, q->filter_list, &res); #ifdef CONFIG_NET_CLS_ACT - switch (tc_classify(skb, q->filter_list, &res)) { + switch (err) { case TC_ACT_STOLEN: case TC_ACT_QUEUED: *qerr = NET_XMIT_SUCCESS; From a289d70d74c39a8e6938619f967fc6cd70ce1798 Mon Sep 17 00:00:00 2001 From: Jesper Bengtsson Date: Thu, 30 Aug 2007 22:36:43 -0700 Subject: [PATCH 19/20] [NETFILTER]: xt_tcpudp: fix wrong struct in udp_checkentry It doesn't seem to have any effect on the x86 architecture but it does have effect on the Axis CRIS architecture. Signed-off-by: Jesper Bengtsson Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_tcpudp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index ab7d845224fc..223f9bded672 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -188,7 +188,7 @@ udp_checkentry(const char *tablename, void *matchinfo, unsigned int hook_mask) { - const struct xt_tcp *udpinfo = matchinfo; + const struct xt_udp *udpinfo = matchinfo; /* Must specify no unknown invflags */ return !(udpinfo->invflags & ~XT_UDP_INV_MASK); From 88282c6ecf0dacefda6090b0289d35e8a3cc6221 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 30 Aug 2007 22:46:36 -0700 Subject: [PATCH 20/20] [PKTGEN]: Remove write-only variable. The pktgen_thread.pid is set to current->pid and is never used after this. So remove this at all. Found during isolating the explicit pid/tgid usage. Signed-off-by: Pavel Emelyanov Acked-by: Sukadev Bhattiprolu Signed-off-by: David S. Miller --- net/core/pktgen.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 4ad62d375373..36fdea71d742 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -380,7 +380,6 @@ struct pktgen_thread { /* Field for thread to receive "posted" events terminate, stop ifs etc. */ u32 control; - int pid; int cpu; wait_queue_head_t queue; @@ -3463,8 +3462,6 @@ static int pktgen_thread_worker(void *arg) init_waitqueue_head(&t->queue); - t->pid = current->pid; - pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid); max_before_softirq = t->max_before_softirq;