From 33c7cfdbb0d2bc021979e4947c7030c30d572532 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:11:01 +0000 Subject: sctp: fix the comment of sctp_sf_violation_paramlen() Update the comment about sctp_sf_violation_paramlen() to be more precise. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 7679208..c085472 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4343,8 +4343,9 @@ static sctp_disposition_t sctp_sf_violation_chunklen( /* * Handle a protocol violation when the parameter length is invalid. - * "Invalid" length is identified as smaller than the minimal length a - * given parameter can be. + * If the length is smaller than the minimum length of a given parameter, + * or accumulated length in multi parameters exceeds the end of the chunk, + * the length is considered as invalid. */ static sctp_disposition_t sctp_sf_violation_paramlen( const struct sctp_endpoint *ep, -- cgit v1.1 From 6a435732accd9e3f4a8d9c320fabe578b1bf5add Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:11:47 +0000 Subject: sctp: use common head of addr parameter to access member in addr-unrelated code The 'p' member of struct sctp_paramhdr is common part for IPv4 addr parameter and IPv6 addr parameter in union sctp_addr_param. For addr-related code, use specified addr parameter. Otherwise, use common header to access type/length member. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/input.c | 2 +- net/sctp/sm_make_chunk.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/input.c b/net/sctp/input.c index 5436c69..30cec77 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1017,7 +1017,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( /* Skip over the ADDIP header and find the Address parameter */ param = (union sctp_addr_param *)(asconf + 1); - af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(param->p.type)); if (unlikely(!af)) return NULL; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index b3434cc..844adfd 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2923,7 +2923,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY) return SCTP_ERROR_UNKNOWN_PARAM; - switch (addr_param->v4.param_hdr.type) { + switch (addr_param->p.type) { case SCTP_PARAM_IPV6_ADDRESS: if (!asoc->peer.ipv6_address) return SCTP_ERROR_DNS_FAILED; @@ -2936,7 +2936,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, return SCTP_ERROR_DNS_FAILED; } - af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(addr_param->p.type)); if (unlikely(!af)) return SCTP_ERROR_DNS_FAILED; @@ -3100,7 +3100,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, /* Skip the address parameter and store a pointer to the first * asconf parameter. */ - length = ntohs(addr_param->v4.param_hdr.length); + length = ntohs(addr_param->p.length); asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); chunk_len -= length; @@ -3177,7 +3177,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, ((void *)asconf_param + sizeof(sctp_addip_param_t)); /* We have checked the packet before, so we do not check again. */ - af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(addr_param->p.type)); af->from_addr_param(&addr, addr_param, htons(bp->port), 0); switch (asconf_param->param_hdr.type) { @@ -3304,7 +3304,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, /* Skip the address parameter in the last asconf sent and store a * pointer to the first asconf parameter. */ - length = ntohs(addr_param->v4.param_hdr.length); + length = ntohs(addr_param->p.length); asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); asconf_len -= length; -- cgit v1.1 From 66009927f1e7374afdc6f9fdd25c493ee4eadf7c Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:12:40 +0000 Subject: sctp: kill abandoned SCTP_CMD_TRANSMIT command Remove SCTP_CMD_TRANSMIT command as it never be used. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/sm_sideeffect.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 5f86ee4b..3b80fe2 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1415,12 +1415,6 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, SCTP_RTXR_T3_RTX); break; - case SCTP_CMD_TRANSMIT: - /* Kick start transmission. */ - error = sctp_outq_uncork(&asoc->outqueue); - local_cork = 0; - break; - case SCTP_CMD_ECN_CE: /* Do delayed CE processing. */ sctp_do_ecn_ce_work(asoc, cmd->obj.u32); -- cgit v1.1 From 934253a7b4ab4151037ea9532552628723a14442 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:13:18 +0000 Subject: sctp: use memdup_user to copy data from userspace Use common function to simply code. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/socket.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index deb82e3..5c9980a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3215,14 +3215,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, if (optlen < sizeof(struct sctp_hmacalgo)) return -EINVAL; - hmacs = kmalloc(optlen, GFP_KERNEL); - if (!hmacs) - return -ENOMEM; - - if (copy_from_user(hmacs, optval, optlen)) { - err = -EFAULT; - goto out; - } + hmacs= memdup_user(optval, optlen); + if (IS_ERR(hmacs)) + return PTR_ERR(hmacs); idents = hmacs->shmac_num_idents; if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || @@ -3257,14 +3252,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk, if (optlen <= sizeof(struct sctp_authkey)) return -EINVAL; - authkey = kmalloc(optlen, GFP_KERNEL); - if (!authkey) - return -ENOMEM; - - if (copy_from_user(authkey, optval, optlen)) { - ret = -EFAULT; - goto out; - } + authkey= memdup_user(optval, optlen); + if (IS_ERR(authkey)) + return PTR_ERR(authkey); if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { ret = -EINVAL; -- cgit v1.1 From f246a7b7c5b9df0ea0f0807a7101995af5e83213 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:13:56 +0000 Subject: sctp: teach CACC algorithm about removed transports When we have have to remove a transport due to ASCONF, we move the data to a new active path. This can trigger CACC algorithm to not mark that data as missing when SACKs arrive. This is because the transport passed to the CACC algorithm is the one this data is sitting on, not the one it was sent on (that one may be gone). So, by sending the original transport (even if it's NULL), we may start marking data as missing. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index bf92a5b..7812772 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -131,7 +131,8 @@ static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, int count_of_newacks) { - if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack) + if (count_of_newacks < 2 && + (transport && !transport->cacc.cacc_saw_newack)) return 1; return 0; } @@ -618,9 +619,12 @@ redo: /* If we are retransmitting, we should only * send a single packet. + * Otherwise, try appending this chunk again. */ if (rtx_timeout || fast_rtx) done = 1; + else + goto redo; /* Bundle next chunk in the next round. */ break; @@ -1683,8 +1687,9 @@ static void sctp_mark_missing(struct sctp_outq *q, /* SFR-CACC may require us to skip marking * this chunk as missing. */ - if (!transport || !sctp_cacc_skip(primary, transport, - count_of_newacks, tsn)) { + if (!transport || !sctp_cacc_skip(primary, + chunk->transport, + count_of_newacks, tsn)) { chunk->tsn_missing_report++; SCTP_DEBUG_PRINTK( -- cgit v1.1 From ee9cbaca7d73ea0098f00ecd10fe6e4a4792e32c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:14:47 +0000 Subject: sctp: Allow bindx_del to accept 0 port We allow 0 port when adding new addresses. It only makes sence to allow 0 port when removing addresses. When removing the currently bound port will be used when the port in the address is set to 0. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/socket.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5c9980a..431b890 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -658,11 +658,15 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) goto err_bindx_rem; } - if (sa_addr->v4.sin_port != htons(bp->port)) { + if (sa_addr->v4.sin_port && + sa_addr->v4.sin_port != htons(bp->port)) { retval = -EINVAL; goto err_bindx_rem; } + if (!sa_addr->v4.sin_port) + sa_addr->v4.sin_port = htons(bp->port); + /* FIXME - There is probably a need to check if sk->sk_saddr and * sk->sk_rcv_addr are currently set to one of the addresses to * be removed. This is something which needs to be looked into -- cgit v1.1 From c6ef006bf57fb6a8a0b134928b5c5606090ef0a0 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:15:22 +0000 Subject: sctp: Release all routes when processing acks ADD_IP or DEL_IP When processing an ACK for ADD_IP parameter, we only release the routes on non-active transports. This can cause a wrong source address to be used. We can release the routes and cause new route lookups and source address selection so that new addresses can be used as source. Additionally, we don't need to lookup routes for all transports at the same time. We can let the transmit code path update the cached route when the transport actually sends something. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 844adfd..f87ccb1 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3193,11 +3193,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, local_bh_enable(); list_for_each_entry(transport, &asoc->peer.transport_addr_list, transports) { - if (transport->state == SCTP_ACTIVE) - continue; dst_release(transport->dst); - sctp_transport_route(transport, NULL, - sctp_sk(asoc->base.sk)); + transport->dst = NULL; } break; case SCTP_PARAM_DEL_IP: @@ -3207,8 +3204,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, list_for_each_entry(transport, &asoc->peer.transport_addr_list, transports) { dst_release(transport->dst); - sctp_transport_route(transport, NULL, - sctp_sk(asoc->base.sk)); + transport->dst = NULL; } break; default: -- cgit v1.1 From 8a00be1c89cc17fda5f438794ff27449af6f00f1 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:25:40 +0000 Subject: sctp: check parameter value of length in ERROR chunk When an endpoint receives ERROR that parameter value is invalid, send an ABORT to peer with a Protocol Violation error code. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/sctp') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index c085472..fe2036d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3204,6 +3204,7 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; + sctp_errhdr_t *err; if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -3212,6 +3213,10 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t))) return sctp_sf_violation_chunklen(ep, asoc, type, arg, commands); + sctp_walk_errors(err, chunk->chunk_hdr); + if ((void *)err != (void *)chunk->chunk_end) + return sctp_sf_violation_paramlen(ep, asoc, type, arg, + (void *)err, commands); sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR, SCTP_CHUNK(chunk)); -- cgit v1.1 From 96ca468b86b09aa6a001ac65dba93a6c4a3692a5 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:26:26 +0000 Subject: sctp: check invalid value of length parameter in error cause RFC4960, section 3.3.7 said: If an endpoint receives an ABORT with a format error or no TCB is found, it MUST silently discard it. When an endpoint receives ABORT that parameter value is invalid, drop it. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index fe2036d..194d5ec 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2412,8 +2412,15 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, /* See if we have an error cause code in the chunk. */ len = ntohs(chunk->chunk_hdr->length); - if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) + if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) { + + sctp_errhdr_t *err; + sctp_walk_errors(err, chunk->chunk_hdr); + if ((void *)err != (void *)chunk->chunk_end) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + } sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET)); /* ASSOC_FAILED will DELETE_TCB. */ -- cgit v1.1 From 0b8f9e25b0aaf5a5d9fd844a97e5c17746b865d4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 19 Apr 2011 21:28:26 +0000 Subject: sctp: remove completely unsed EMPTY state SCTP does not SCTP_STATE_EMPTY and we can never be in that state. Remove useless code. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/debug.c | 1 - net/sctp/outqueue.c | 1 - net/sctp/sm_statetable.c | 76 ------------------------------------------------ 3 files changed, 78 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/debug.c b/net/sctp/debug.c index bf24fa6..ec997cf 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -98,7 +98,6 @@ const char *sctp_cname(const sctp_subtype_t cid) /* These are printable forms of the states. */ const char *const sctp_state_tbl[SCTP_STATE_NUM_STATES] = { - "STATE_EMPTY", "STATE_CLOSED", "STATE_COOKIE_WAIT", "STATE_COOKIE_ECHOED", diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 7812772..3e9d8d2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -320,7 +320,6 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) * chunk. */ switch (q->asoc->state) { - case SCTP_STATE_EMPTY: case SCTP_STATE_CLOSED: case SCTP_STATE_SHUTDOWN_PENDING: case SCTP_STATE_SHUTDOWN_SENT: diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 546d4387..881196b 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -107,8 +107,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, #define TYPE_SCTP_FUNC(func) {.fn = func, .name = #func} #define TYPE_SCTP_DATA { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -128,8 +126,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_DATA */ #define TYPE_SCTP_INIT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_1B_init), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -149,8 +145,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_INIT */ #define TYPE_SCTP_INIT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_2_3_initack), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -170,8 +164,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_INIT_ACK */ #define TYPE_SCTP_SACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -191,8 +183,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SACK */ #define TYPE_SCTP_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -213,8 +203,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_HEARTBEAT */ #define TYPE_SCTP_HEARTBEAT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -234,8 +222,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_HEARTBEAT_ACK */ #define TYPE_SCTP_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_pdiscard), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -255,8 +241,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ABORT */ #define TYPE_SCTP_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -276,8 +260,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SHUTDOWN */ #define TYPE_SCTP_SHUTDOWN_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -297,8 +279,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SHUTDOWN_ACK */ #define TYPE_SCTP_ERROR { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -318,8 +298,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ERROR */ #define TYPE_SCTP_COOKIE_ECHO { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_1D_ce), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -339,8 +317,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_COOKIE_ECHO */ #define TYPE_SCTP_COOKIE_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -360,8 +336,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_COOKIE_ACK */ #define TYPE_SCTP_ECN_ECNE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -381,8 +355,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ECN_ECNE */ #define TYPE_SCTP_ECN_CWR { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -402,8 +374,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ECN_CWR */ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -446,8 +416,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][ }; /* state_fn_t chunk_event_table[][] */ #define TYPE_SCTP_ASCONF { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -467,8 +435,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][ } /* TYPE_SCTP_ASCONF */ #define TYPE_SCTP_ASCONF_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -496,8 +462,6 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_ }; /*state_fn_t addip_chunk_event_table[][] */ #define TYPE_SCTP_FWD_TSN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -524,8 +488,6 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN }; /*state_fn_t prsctp_chunk_event_table[][] */ #define TYPE_SCTP_AUTH { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -553,8 +515,6 @@ static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TY static const sctp_sm_table_entry_t chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { - /* SCTP_STATE_EMPTY */ - TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_CLOSED */ TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_COOKIE_WAIT */ @@ -575,8 +535,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { #define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_prm_asoc), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -596,8 +554,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ #define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -617,8 +573,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ #define TYPE_SCTP_PRIMITIVE_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -638,8 +592,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_ABORT */ #define TYPE_SCTP_PRIMITIVE_SEND { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -659,8 +611,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_SEND */ #define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -680,8 +630,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ #define TYPE_SCTP_PRIMITIVE_ASCONF { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -713,8 +661,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE }; #define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -734,8 +680,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE } #define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -760,8 +704,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ }; #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -781,8 +723,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -802,8 +742,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -823,8 +761,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -844,8 +780,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -865,8 +799,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -886,8 +818,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -907,8 +837,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -928,8 +856,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -949,8 +875,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ -- cgit v1.1 From deb85a6ecc432a4f342004a6ac2a0dad7cba6846 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 19 Apr 2011 21:29:23 +0000 Subject: sctp: bail from sctp_endpoint_lookup_assoc() if not bound The sctp_endpoint_lookup_assoc() function uses a port hash to lookup the association and then checks to see if any of them are on the current endpoint. However, if the current endpoint is not bound, there can't be any associations on it, thus we can bail early. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/endpointola.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e10acc0..c8cc24e 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -325,6 +325,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( struct sctp_transport **transport) { struct sctp_association *asoc = NULL; + struct sctp_association *tmp; struct sctp_transport *t = NULL; struct sctp_hashbucket *head; struct sctp_ep_common *epb; @@ -333,25 +334,32 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( int rport; *transport = NULL; + + /* If the local port is not set, there can't be any associations + * on this endpoint. + */ + if (!ep->base.bind_addr.port) + goto out; + rport = ntohs(paddr->v4.sin_port); hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); sctp_for_each_hentry(epb, node, &head->chain) { - asoc = sctp_assoc(epb); - if (asoc->ep != ep || rport != asoc->peer.port) - goto next; + tmp = sctp_assoc(epb); + if (tmp->ep != ep || rport != tmp->peer.port) + continue; - t = sctp_assoc_lookup_paddr(asoc, paddr); + t = sctp_assoc_lookup_paddr(tmp, paddr); if (t) { + asoc = tmp; *transport = t; break; } -next: - asoc = NULL; } read_unlock(&head->lock); +out: return asoc; } -- cgit v1.1 From 85c5ed4e44a262344ce43b4bf23204107923ca95 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:30:01 +0000 Subject: sctp: handle ootb packet in chunk order as defined Changed the order of processing SHUTDOWN ACK and COOKIE ACK refer to section 8.4:Handle "Out of the Blue" Packets. SHUTDOWN ACK chunk should be processed before processing "Stale Cookie" ERROR or a COOKIE ACK. Signed-off-by: Wei Yongjun Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/input.c | 15 --------------- net/sctp/sm_statefuns.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/input.c b/net/sctp/input.c index 30cec77..3a8eb79 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -661,7 +661,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb) { sctp_chunkhdr_t *ch; __u8 *ch_end; - sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; @@ -697,20 +696,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb) if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data) goto discard; - /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR - * or a COOKIE ACK the SCTP Packet should be silently - * discarded. - */ - if (SCTP_CID_COOKIE_ACK == ch->type) - goto discard; - - if (SCTP_CID_ERROR == ch->type) { - sctp_walk_errors(err, ch) { - if (SCTP_ERROR_STALE_COOKIE == err->cause) - goto discard; - } - } - ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb_tail_pointer(skb)); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 194d5ec..ad3b43b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3332,8 +3332,10 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; + sctp_errhdr_t *err; __u8 *ch_end; int ootb_shut_ack = 0; + int ootb_cookie_ack = 0; SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES); @@ -3358,6 +3360,23 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, if (SCTP_CID_ABORT == ch->type) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR + * or a COOKIE ACK the SCTP Packet should be silently + * discarded. + */ + + if (SCTP_CID_COOKIE_ACK == ch->type) + ootb_cookie_ack = 1; + + if (SCTP_CID_ERROR == ch->type) { + sctp_walk_errors(err, ch) { + if (SCTP_ERROR_STALE_COOKIE == err->cause) { + ootb_cookie_ack = 1; + break; + } + } + } + /* Report violation if chunk len overflows */ ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); if (ch_end > skb_tail_pointer(skb)) @@ -3369,6 +3388,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, if (ootb_shut_ack) return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); + else if (ootb_cookie_ack) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); else return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); } -- cgit v1.1 From de6becdc0844ff92b38ffd9f0c4db1d3de02835f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:30:51 +0000 Subject: sctp: fix to check the source address of COOKIE-ECHO chunk SCTP does not check whether the source address of COOKIE-ECHO chunk is the original address of INIT chunk or part of the any address parameters saved in COOKIE in CLOSED state. So even if the COOKIE-ECHO chunk is from any address but with correct COOKIE, the COOKIE-ECHO chunk still be accepted. If the COOKIE is not from a valid address, the assoc should not be established. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 26 +++++++++++++++++++++----- net/sctp/sm_sideeffect.c | 3 +-- net/sctp/sm_statefuns.c | 14 +++++--------- 3 files changed, 27 insertions(+), 16 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f87ccb1..a7b65e9 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2242,14 +2242,17 @@ int sctp_verify_init(const struct sctp_association *asoc, * Returns 0 on failure, else success. * FIXME: This is an association method. */ -int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, gfp_t gfp) { union sctp_params param; struct sctp_transport *transport; struct list_head *pos, *temp; + struct sctp_af *af; + union sctp_addr addr; char *cookie; + int src_match = 0; /* We must include the address that the INIT packet came from. * This is the only address that matters for an INIT packet. @@ -2261,18 +2264,31 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, * added as the primary transport. The source address seems to * be a a better choice than any of the embedded addresses. */ - if (peer_addr) { - if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) - goto nomem; - } + if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) + goto nomem; + + if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) + src_match = 1; /* Process the initialization parameters. */ sctp_walk_params(param, peer_init, init_hdr.params) { + if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS || + param.p->type == SCTP_PARAM_IPV6_ADDRESS)) { + af = sctp_get_af_specific(param_type2af(param.p->type)); + af->from_addr_param(&addr, param.addr, + chunk->sctp_hdr->source, 0); + if (sctp_cmp_addr_exact(sctp_source(chunk), &addr)) + src_match = 1; + } if (!sctp_process_param(asoc, param, peer_addr, gfp)) goto clean_up; } + /* source address of chunk may not match any valid address */ + if (!src_match) + goto clean_up; + /* AUTH: After processing the parameters, make sure that we * have all the required info to potentially do authentications. */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 3b80fe2..d612ca1 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -595,8 +595,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, * fail during INIT processing (due to malloc problems), * just return the error and stop processing the stack. */ - if (!sctp_process_init(asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, gfp)) + if (!sctp_process_init(asoc, chunk, sctp_source(chunk), peer_init, gfp)) error = -ENOMEM; else error = 0; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ad3b43b..ab94932 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -393,8 +393,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, goto nomem_init; /* The call, sctp_process_init(), can fail on memory allocation. */ - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem_init; @@ -725,7 +724,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + if (!sctp_process_init(new_asoc, chunk, &chunk->subh.cookie_hdr->c.peer_addr, peer_init, GFP_ATOMIC)) goto nomem_init; @@ -1464,8 +1463,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( * Verification Tag and Peers Verification tag into a reserved * place (local tie-tag and per tie-tag) within the state cookie. */ - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem; @@ -1694,8 +1692,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1780,8 +1777,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; -- cgit v1.1 From 92c73af58e9f1b487322ce25a7a67889c9d91343 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:31:47 +0000 Subject: sctp: make heartbeat information in sctp_make_heartbeat() Make heartbeat information in sctp_make_heartbeat() instead of make it in sctp_sf_heartbeat() directly for common using. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 18 +++++++++++++----- net/sctp/sm_statefuns.c | 11 +---------- 2 files changed, 14 insertions(+), 15 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index a7b65e9..58eb27f 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1075,20 +1075,28 @@ nodata: /* Make a HEARTBEAT chunk. */ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, - const struct sctp_transport *transport, - const void *payload, const size_t paylen) + const struct sctp_transport *transport) { - struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, - 0, paylen); + struct sctp_chunk *retval; + sctp_sender_hb_info_t hbinfo; + + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); if (!retval) goto nodata; + hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; + hbinfo.hb_nonce = transport->hb_nonce; + /* Cast away the 'const', as this is just telling the chunk * what transport it belongs to. */ retval->transport = (struct sctp_transport *) transport; - retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo), + &hbinfo); nodata: return retval; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ab94932..736847e4 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -941,18 +941,9 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep, { struct sctp_transport *transport = (struct sctp_transport *) arg; struct sctp_chunk *reply; - sctp_sender_hb_info_t hbinfo; - size_t paylen = 0; - - hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; - hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); - hbinfo.daddr = transport->ipaddr; - hbinfo.sent_at = jiffies; - hbinfo.hb_nonce = transport->hb_nonce; /* Send a heartbeat to our peer. */ - paylen = sizeof(sctp_sender_hb_info_t); - reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); + reply = sctp_make_heartbeat(asoc, transport); if (!reply) return SCTP_DISPOSITION_NOMEM; -- cgit v1.1 From 4c6a6f42131dd750dcfe3c71e63bfc046e5a227e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:32:28 +0000 Subject: sctp: move chunk from retransmit queue to abandoned list If there is still data waiting to retransmit and remain in retransmit queue, while doing the next retransmit, if the chunk is abandoned, we should move it to abandoned list. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/sctp') diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 3e9d8d2..1c88c89 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -577,6 +577,13 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, * try to send as much as possible. */ list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) { + /* If the chunk is abandoned, move it to abandoned list. */ + if (sctp_chunk_abandoned(chunk)) { + list_del_init(&chunk->transmitted_list); + sctp_insert_list(&q->abandoned, + &chunk->transmitted_list); + continue; + } /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the -- cgit v1.1 From 209ba424c2c6e5ff4dd0ff79bb23659aa6048eac Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:27:08 +0000 Subject: sctp: implement socket option SCTP_GET_ASSOC_ID_LIST This patch Implement socket option SCTP_GET_ASSOC_ID_LIST. SCTP Socket API Extension: 8.2.6. Get the Current Identifiers of Associations (SCTP_GET_ASSOC_ID_LIST) This option gets the current list of SCTP association identifiers of the SCTP associations handled by a one-to-many style socket. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'net/sctp') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 431b890..f694ee1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5277,6 +5277,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, return 0; } +/* + * 8.2.6. Get the Current Identifiers of Associations + * (SCTP_GET_ASSOC_ID_LIST) + * + * This option gets the current list of SCTP association identifiers of + * the SCTP associations handled by a one-to-many style socket. + */ +static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_assoc_ids *ids; + u32 num = 0; + + if (sctp_style(sk, TCP)) + return -EOPNOTSUPP; + + if (len < sizeof(struct sctp_assoc_ids)) + return -EINVAL; + + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + num++; + } + + if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) + return -EINVAL; + + len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; + + ids = kmalloc(len, GFP_KERNEL); + if (unlikely(!ids)) + return -ENOMEM; + + ids->gaids_number_of_ids = num; + num = 0; + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + ids->gaids_assoc_id[num++] = asoc->assoc_id; + } + + if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { + kfree(ids); + return -EFAULT; + } + + kfree(ids); + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5409,6 +5458,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_GET_ASSOC_NUMBER: retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); break; + case SCTP_GET_ASSOC_ID_LIST: + retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; -- cgit v1.1 From ee916fd0fdb8f43dacaab431de3e1f7225039d72 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:28:01 +0000 Subject: sctp: change auth event type name to SCTP_AUTHENTICATION_EVENT This patch change the auth event type name to SCTP_AUTHENTICATION_EVENT, which is based on API extension compliance. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/ulpevent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index dff27d5..62d4a7b 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -843,7 +843,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey( ak = (struct sctp_authkey_event *) skb_put(skb, sizeof(struct sctp_authkey_event)); - ak->auth_type = SCTP_AUTHENTICATION_INDICATION; + ak->auth_type = SCTP_AUTHENTICATION_EVENT; ak->auth_flags = 0; ak->auth_length = sizeof(struct sctp_authkey_event); -- cgit v1.1 From e1cdd553d482ceb083fac5e544e8702fccefbfd6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:29:03 +0000 Subject: sctp: implement event notification SCTP_SENDER_DRY_EVENT This patch implement event notification SCTP_SENDER_DRY_EVENT. SCTP Socket API Extensions: 6.1.9. SCTP_SENDER_DRY_EVENT When the SCTP stack has no more user data to send or retransmit, this notification is given to the user. Also, at the time when a user app subscribes to this event, if there is no data to be sent or retransmit, the stack will immediately send up this notification. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 24 ++++++++++++++++++++++++ net/sctp/sm_statetable.c | 2 +- net/sctp/ulpevent.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 736847e4..7f4a4f8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5077,6 +5077,30 @@ sctp_disposition_t sctp_sf_ignore_primitive( ***************************************************************************/ /* + * When the SCTP stack has no more user data to send or retransmit, this + * notification is given to the user. Also, at the time when a user app + * subscribes to this event, if there is no data to be sent or + * retransmit, the stack will immediately send up this notification. + */ +sctp_disposition_t sctp_sf_do_no_pending_tsn( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_ulpevent *event; + + event = sctp_ulpevent_make_sender_dry_event(asoc, GFP_ATOMIC); + if (!event) + return SCTP_DISPOSITION_NOMEM; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* * Start the shutdown negotiation. * * From Section 9.2: diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 881196b..0338dc6 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -668,7 +668,7 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE /* SCTP_STATE_COOKIE_ECHOED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_ESTABLISHED */ \ - TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ + TYPE_SCTP_FUNC(sctp_sf_do_no_pending_tsn), \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ TYPE_SCTP_FUNC(sctp_sf_do_9_2_start_shutdown), \ /* SCTP_STATE_SHUTDOWN_SENT */ \ diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 62d4a7b..c962c60 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -862,6 +862,34 @@ fail: return NULL; } +/* + * Socket Extensions for SCTP + * 6.3.10. SCTP_SENDER_DRY_EVENT + */ +struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( + const struct sctp_association *asoc, gfp_t gfp) +{ + struct sctp_ulpevent *event; + struct sctp_sender_dry_event *sdry; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event), + MSG_NOTIFICATION, gfp); + if (!event) + return NULL; + + skb = sctp_event2skb(event); + sdry = (struct sctp_sender_dry_event *) + skb_put(skb, sizeof(struct sctp_sender_dry_event)); + + sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT; + sdry->sender_dry_flags = 0; + sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event); + sctp_ulpevent_set_owner(event, asoc); + sdry->sender_dry_assoc_id = sctp_assoc2id(asoc); + + return event; +} /* Return the notification type, assuming this is a notification * event. -- cgit v1.1 From b71d1d426d263b0b6cb5760322efebbfc89d4463 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Apr 2011 04:53:02 +0000 Subject: inet: constify ip headers and in6_addr Add const qualifiers to structs iphdr, ipv6hdr and in6_addr pointers where possible, to make code intention more obvious. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/input.c | 2 +- net/sctp/ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/input.c b/net/sctp/input.c index 3a8eb79..741ed16 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -565,7 +565,7 @@ void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) */ void sctp_v4_err(struct sk_buff *skb, __u32 info) { - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; const int ihlen = iph->ihl * 4; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 865ce7b..321f175 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -531,7 +531,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) { int type; - struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; + const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr; type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) -- cgit v1.1 From 625034113bd45c71fb9e329f52f25fef9e6993a3 Mon Sep 17 00:00:00 2001 From: Weixing Shi Date: Tue, 26 Apr 2011 21:36:32 +0000 Subject: sctp: fix sctp to work with ipv6 source address routing In the below test case, using the source address routing, sctp can not work. Node-A 1)ifconfig eth0 inet6 add 2001:1::1/64 2)ip -6 rule add from 2001:1::1 table 100 pref 100 3)ip -6 route add 2001:2::1 dev eth0 table 100 4)sctp_darn -H 2001:1::1 -P 250 -l & Node-B 1)ifconfig eth0 inet6 add 2001:2::1/64 2)ip -6 rule add from 2001:2::1 table 100 pref 100 3)ip -6 route add 2001:1::1 dev eth0 table 100 4)sctp_darn -H 2001:2::1 -P 250 -h 2001:1::1 -p 250 -s root cause: Node-A and Node-B use the source address routing, and at begining, source address will be NULL,sctp will search the routing table by the destination address, because using the source address routing table, and the result dst_entry will be NULL. solution: walk through the bind address list to get the source address and then lookup the routing table again to get the correct dst_entry. Signed-off-by: Weixing Shi Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 321f175..3a571d6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -80,6 +80,9 @@ #include +static inline int sctp_v6_addr_match_len(union sctp_addr *s1, + union sctp_addr *s2); + /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same @@ -244,8 +247,14 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, union sctp_addr *saddr) { - struct dst_entry *dst; + struct dst_entry *dst = NULL; struct flowi6 fl6; + struct sctp_bind_addr *bp; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *baddr = NULL; + __u8 matchlen = 0; + __u8 bmatchlen; + sctp_scope_t scope; memset(&fl6, 0, sizeof(fl6)); ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); @@ -261,6 +270,39 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, } dst = ip6_route_output(&init_net, NULL, &fl6); + if (!asoc || saddr) + goto out; + + if (dst->error) { + dst_release(dst); + dst = NULL; + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* Walk through the bind address list and try to get a dst that + * matches a bind address as the source address. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid) + continue; + if ((laddr->state == SCTP_ADDR_SRC) && + (laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, + &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } + } + } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); + dst = ip6_route_output(&init_net, NULL, &fl6); + } + } +out: if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; -- cgit v1.1 From 9914ae3ca770389a3bec3114d0a07532a7f235dd Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:51:31 +0000 Subject: sctp: cache the ipv6 source after route lookup The ipv6 routing lookup does give us a source address, but instead of filling it into the dst, it's stored in the flowi. We can use that instead of going through the entire source address selection again. Also the useless ->dst_saddr member of sctp_pf is removed. And sctp_v6_dst_saddr() is removed, instead by introduce sctp_v6_to_addr(), which can be reused to cleanup some dup code. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 161 +++++++++++++++++++++++---------------------------- net/sctp/protocol.c | 47 +++++++-------- net/sctp/socket.c | 2 +- net/sctp/transport.c | 15 +++-- 4 files changed, 106 insertions(+), 119 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3a571d6..51c048d 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -82,6 +82,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, union sctp_addr *s2); +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, + __be16 port); +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2); /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since @@ -245,73 +249,99 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) */ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct dst_entry *dst = NULL; - struct flowi6 fl6; + struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; + int err = 0; - memset(&fl6, 0, sizeof(fl6)); - ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); + memset(fl6, 0, sizeof(struct flowi6)); + ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) - fl6.flowi6_oif = daddr->v6.sin6_scope_id; + fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr); + SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (saddr) { - ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr); + ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - dst = ip6_route_output(&init_net, NULL, &fl6); + err = ip6_dst_lookup(sk, &dst, fl6); if (!asoc || saddr) goto out; - if (dst->error) { - dst_release(dst); - dst = NULL; - bp = &asoc->base.bind_addr; - scope = sctp_scope(daddr); - /* Walk through the bind address list and try to get a dst that - * matches a bind address as the source address. + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* ip6_dst_lookup has filled in the fl6->saddr for us. Check + * to see if we can use it. + */ + if (!err) { + /* Walk through the bind address list and look for a bind + * address that matches the source address of the returned dst. */ + sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) + if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, - &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } + + /* Do not compare against v4 addrs */ + if ((laddr->a.sa.sa_family == AF_INET6) && + (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { + rcu_read_unlock(); + goto out; } } rcu_read_unlock(); - if (baddr) { - ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); - dst = ip6_route_output(&init_net, NULL, &fl6); + /* None of the bound addresses match the source address of the + * dst. So release it. + */ + dst_release(dst); + dst = NULL; + } + + /* Walk through the bind address list and try to get the + * best source address for a given destination. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) + continue; + if ((laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } } } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); + err = ip6_dst_lookup(sk, &dst, fl6); + } + out: - if (!dst->error) { + if (!err) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", - &rt->rt6i_dst.addr, &rt->rt6i_src.addr); + &rt->rt6i_dst.addr, &fl6->saddr); return dst; } SCTP_DEBUG_PRINTK("NO ROUTE\n"); - dst_release(dst); return NULL; } @@ -328,64 +358,21 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, * and asoc's bind address list. */ static void sctp_v6_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct sctp_bind_addr *bp; - struct sctp_sockaddr_entry *laddr; - sctp_scope_t scope; - union sctp_addr *baddr = NULL; - __u8 matchlen = 0; - __u8 bmatchlen; + struct flowi6 *fl6 = &fl->u.ip6; + union sctp_addr *saddr = &t->saddr; SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, asoc, dst, &daddr->v6.sin6_addr); - - if (!asoc) { - ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), - dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, - inet6_sk(&sk->inet.sk)->srcprefs, - &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", - &saddr->v6.sin6_addr); - return; - } - - scope = sctp_scope(daddr); + __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - bp = &asoc->base.bind_addr; - - /* Go through the bind address list and find the best source address - * that matches the scope of the destination address. - */ - rcu_read_lock(); - list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) - continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } - } - } - if (baddr) { - memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); - } else { - pr_err("%s: asoc:%p Could not find a valid source " - "address for the dest:%pI6\n", - __func__, asoc, &daddr->v6.sin6_addr); + if (t->dst) { + saddr->v6.sin6_family = AF_INET6; + ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr); } - - rcu_read_unlock(); } /* Make a copy of all potential local addresses. */ @@ -507,14 +494,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr, return length; } -/* Initialize a sctp_addr from a dst_entry. */ -static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, +/* Initialize a sctp_addr from struct in6_addr. */ +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, __be16 port) { - struct rt6_info *rt = (struct rt6_info *)dst; addr->sa.sa_family = AF_INET6; addr->v6.sin6_port = port; - ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); + ipv6_addr_copy(&addr->v6.sin6_addr, saddr); } /* Compare addresses exactly. @@ -1001,7 +987,6 @@ static struct sctp_af sctp_af_inet6 = { .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, - .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5bf91d..3421645 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -465,33 +465,35 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) */ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct rtable *rt; - struct flowi4 fl4; + struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; union sctp_addr dst_saddr; - memset(&fl4, 0x0, sizeof(struct flowi4)); - fl4.daddr = daddr->v4.sin_addr.s_addr; - fl4.fl4_dport = daddr->v4.sin_port; - fl4.flowi4_proto = IPPROTO_SCTP; + memset(fl4, 0x0, sizeof(struct flowi4)); + fl4->daddr = daddr->v4.sin_addr.s_addr; + fl4->fl4_dport = daddr->v4.sin_port; + fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { - fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); - fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if; - fl4.fl4_sport = htons(asoc->base.bind_addr.port); + fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); + fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; + fl4->fl4_sport = htons(asoc->base.bind_addr.port); } if (saddr) { - fl4.saddr = saddr->v4.sin_addr.s_addr; - fl4.fl4_sport = saddr->v4.sin_port; + fl4->saddr = saddr->v4.sin_addr.s_addr; + fl4->fl4_sport = saddr->v4.sin_port; } SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", - __func__, &fl4.daddr, &fl4.saddr); + __func__, &fl4->daddr, &fl4->saddr); - rt = ip_route_output_key(&init_net, &fl4); + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) dst = &rt->dst; @@ -533,9 +535,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, continue; if ((laddr->state == SCTP_ADDR_SRC) && (AF_INET == laddr->a.sa.sa_family)) { - fl4.saddr = laddr->a.v4.sin_addr.s_addr; - fl4.fl4_sport = laddr->a.v4.sin_port; - rt = ip_route_output_key(&init_net, &fl4); + fl4->saddr = laddr->a.v4.sin_addr.s_addr; + fl4->fl4_sport = laddr->a.v4.sin_port; + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) { dst = &rt->dst; goto out_unlock; @@ -559,19 +561,15 @@ out: * to cache it separately and hence this is an empty routine. */ static void sctp_v4_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct rtable *rt = (struct rtable *)dst; - - if (!asoc) - return; + union sctp_addr *saddr = &t->saddr; + struct rtable *rt = (struct rtable *)t->dst; if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_port = htons(asoc->base.bind_addr.port); saddr->v4.sin_addr.s_addr = rt->rt_src; } } @@ -950,7 +948,6 @@ static struct sctp_af sctp_af_inet = { .to_sk_daddr = sctp_v4_to_sk_daddr, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, - .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f694ee1..33d9ee6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2287,7 +2287,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, trans->param_flags = (trans->param_flags & ~SPP_PMTUD) | pmtud_change; if (update) { - sctp_transport_pmtu(trans); + sctp_transport_pmtu(trans, sctp_opt2sk(sp)); sctp_assoc_sync_pmtu(asoc); } } else if (asoc) { diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d3ae493..2544b9b 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -211,11 +211,15 @@ void sctp_transport_set_owner(struct sctp_transport *transport, } /* Initialize the pmtu of a transport. */ -void sctp_transport_pmtu(struct sctp_transport *transport) +void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { struct dst_entry *dst; + struct flowi fl; - dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL); + dst = transport->af_specific->get_dst(transport->asoc, + &transport->ipaddr, + &transport->saddr, + &fl, sk); if (dst) { transport->pathmtu = dst_mtu(dst); @@ -272,15 +276,16 @@ void sctp_transport_route(struct sctp_transport *transport, struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; struct dst_entry *dst; + struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr); + dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); + transport->dst = dst; if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, asoc, dst, daddr, &transport->saddr); + af->get_saddr(opt, transport, daddr, &fl); - transport->dst = dst; if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } -- cgit v1.1 From 9c6a02f41d10dc9fbf5dd42058e8846f38dd2d9a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:52:27 +0000 Subject: sctp: make sctp over IPv6 work with IPsec SCTP never called xfrm_output after it's v6 route lookups so that never really worked with ipsec. Additioanlly, we never passed port nubmers and protocol in the flowi, so any port based policies were never applied as well. Now that we can fixed ipv6 routing lookup code, using ip6_dst_lookup_flow() and pass port numbers. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 51c048d..593c801 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -262,22 +262,27 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; - int err = 0; memset(fl6, 0, sizeof(struct flowi6)); ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); + fl6->fl6_dport = daddr->v6.sin6_port; + fl6->flowi6_proto = IPPROTO_SCTP; if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); + if (asoc) + fl6->fl6_sport = htons(asoc->base.bind_addr.port); + if (saddr) { ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + fl6->fl6_sport = saddr->v6.sin6_port; SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - err = ip6_dst_lookup(sk, &dst, fl6); + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); if (!asoc || saddr) goto out; @@ -286,7 +291,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, /* ip6_dst_lookup has filled in the fl6->saddr for us. Check * to see if we can use it. */ - if (!err) { + if (!IS_ERR(dst)) { /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ @@ -330,11 +335,12 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, rcu_read_unlock(); if (baddr) { ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); - err = ip6_dst_lookup(sk, &dst, fl6); + fl6->fl6_sport = baddr->v6.sin6_port; + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); } out: - if (!err) { + if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", -- cgit v1.1 From af1384703f8a4ff3d245925d6596ef1c5c6e469e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:53:20 +0000 Subject: sctp: remove useless arguments from get_saddr() call There is no point in passing a destination address to a get_saddr() call. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 5 +---- net/sctp/protocol.c | 1 - net/sctp/transport.c | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 593c801..a1913a4 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -365,15 +365,12 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, */ static void sctp_v6_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { struct flowi6 *fl6 = &fl->u.ip6; union sctp_addr *saddr = &t->saddr; - SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - + SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst); if (t->dst) { saddr->v6.sin6_family = AF_INET6; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3421645..68b4c43 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -562,7 +562,6 @@ out: */ static void sctp_v4_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { union sctp_addr *saddr = &t->saddr; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2544b9b..1fbb920 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -284,7 +284,7 @@ void sctp_transport_route(struct sctp_transport *transport, if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, transport, daddr, &fl); + af->get_saddr(opt, transport, &fl); if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; -- cgit v1.1 From da0420bee24a1ba54e55a61e95b1a53205d7e62d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:54:17 +0000 Subject: sctp: clean up route lookup calls Change the call to take the transport parameter and set the cached 'dst' appropriately inside the get_dst() function calls. This will allow us in the future to clean up source address storage as well. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 17 ++++++++--------- net/sctp/protocol.c | 12 +++++------- net/sctp/transport.c | 23 ++++++++++------------- 3 files changed, 23 insertions(+), 29 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a1913a4..500875f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -247,17 +247,16 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) /* Returns the dst cache entry for the given source and destination ip * addresses. */ -static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct dst_entry *dst = NULL; struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; @@ -270,7 +269,6 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (asoc) @@ -343,12 +341,13 @@ out: if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; + t->dst = dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr, &fl6->saddr); - return dst; + } else { + t->dst = NULL; + SCTP_DEBUG_PRINTK("NO ROUTE\n"); } - SCTP_DEBUG_PRINTK("NO ROUTE\n"); - return NULL; } /* Returns the number of consecutive initial bits that match in the 2 ipv6 diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 68b4c43..9d3f159 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -463,17 +463,16 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) * addresses. If an association is passed, trys to get a dst entry with a * source address that matches an address in the bind address list. */ -static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct rtable *rt; struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; memset(fl4, 0x0, sizeof(struct flowi4)); @@ -548,13 +547,12 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, out_unlock: rcu_read_unlock(); out: + t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", &rt->rt_dst, &rt->rt_src); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); - - return dst; } /* For v4, the source address is cached in the route entry(dst). So no need diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 1fbb920..d8595dd 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -213,17 +213,17 @@ void sctp_transport_set_owner(struct sctp_transport *transport, /* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { - struct dst_entry *dst; struct flowi fl; - dst = transport->af_specific->get_dst(transport->asoc, - &transport->ipaddr, - &transport->saddr, + /* If we don't have a fresh route, look one up */ + if (!transport->dst || transport->dst->obsolete > 1) { + dst_release(transport->dst); + transport->af_specific->get_dst(transport, &transport->saddr, &fl, sk); + } - if (dst) { - transport->pathmtu = dst_mtu(dst); - dst_release(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); } else transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } @@ -274,12 +274,9 @@ void sctp_transport_route(struct sctp_transport *transport, { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; - union sctp_addr *daddr = &transport->ipaddr; - struct dst_entry *dst; struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); - transport->dst = dst; + af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt)); if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); @@ -289,8 +286,8 @@ void sctp_transport_route(struct sctp_transport *transport, if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } - if (dst) { - transport->pathmtu = dst_mtu(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). -- cgit v1.1 From 18a353f42817f08e3501162ceda9d2efddb08a40 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:55:05 -0700 Subject: sctp: Use flowi4's {saddr,daddr} in sctp_v4_dst_saddr() and sctp_v4_get_dst() Instead of rt->rt_{src,dst} Signed-off-by: David S. Miller --- net/sctp/protocol.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 9d3f159..69fbc55 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -339,13 +339,12 @@ static int sctp_v4_to_addr_param(const union sctp_addr *addr, } /* Initialize a sctp_addr from a dst_entry. */ -static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, +static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4, __be16 port) { - struct rtable *rt = (struct rtable *)dst; saddr->v4.sin_family = AF_INET; saddr->v4.sin_port = port; - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl4->saddr; } /* Compare two addresses exactly. */ @@ -508,7 +507,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ - sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port)); + sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) @@ -550,7 +549,7 @@ out: t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", - &rt->rt_dst, &rt->rt_src); + &fl4->daddr, &fl4->saddr); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); } -- cgit v1.1 From 8663c938ceb72f47941c95ff0ea491ebbdd68f26 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:32:47 -0700 Subject: sctp: Store a flowi in transports to provide persistent keying. Several future simplifications are possible now because of this. For example, the sctp_addr unions can simply refer directly to the flowi information. Signed-off-by: David S. Miller --- net/sctp/transport.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d8595dd..394c57c 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -213,13 +213,11 @@ void sctp_transport_set_owner(struct sctp_transport *transport, /* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { - struct flowi fl; - /* If we don't have a fresh route, look one up */ if (!transport->dst || transport->dst->obsolete > 1) { dst_release(transport->dst); transport->af_specific->get_dst(transport, &transport->saddr, - &fl, sk); + &transport->fl, sk); } if (transport->dst) { @@ -274,14 +272,13 @@ void sctp_transport_route(struct sctp_transport *transport, { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; - struct flowi fl; - af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt)); + af->get_dst(transport, saddr, &transport->fl, sctp_opt2sk(opt)); if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, transport, &fl); + af->get_saddr(opt, transport, &transport->fl); if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; -- cgit v1.1 From d9d8da805dcb503ef8ee49918a94d49085060f23 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:23:20 -0700 Subject: inet: Pass flowi to ->queue_xmit(). This allows us to acquire the exact route keying information from the protocol, however that might be managed. It handles all of the possibilities, from the simplest case of storing the key in inet->cork.fl to the more complex setup SCTP has where individual transports determine the flow. Signed-off-by: David S. Miller --- net/sctp/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 69fbc55..847193b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -855,7 +855,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, IP_PMTUDISC_DO : IP_PMTUDISC_DONT; SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); - return ip_queue_xmit(skb); + return ip_queue_xmit(skb, &transport->fl); } static struct sctp_af sctp_af_inet; -- cgit v1.1 From f1c0a276ea1786213bda2313cd9034f3a23f2e77 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:34:29 -0700 Subject: sctp: Don't use rt->rt_{src,dst} in sctp_v4_xmit() Now we can pick it out of the transport's flow key. Signed-off-by: David S. Miller --- net/sctp/protocol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 847193b..acb2ee7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - &skb_rtable(skb)->rt_src, - &skb_rtable(skb)->rt_dst); + transport->fl.u.ip4.saddr, + transport->fl.u.ip4.daddr); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; -- cgit v1.1 From 7ef73bca731fea9d4b706db2acb96b6488aa1b0e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 21:14:41 -0700 Subject: sctp: Fix debug message args. I messed things up when I converted over to the transport flow, I passed the ipv4 address value instead of it's address. Reported-by: Stephen Rothwell Signed-off-by: David S. Miller --- net/sctp/protocol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index acb2ee7..4f270ac 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - transport->fl.u.ip4.saddr, - transport->fl.u.ip4.daddr); + &transport->fl.u.ip4.saddr, + &transport->fl.u.ip4.daddr); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; -- cgit v1.1 From 902ebd3e0de618b6d39004edac00b2cc36362065 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 14:49:13 -0700 Subject: sctp: Remove rt->rt_src usage in sctp_v4_get_saddr() Flow key is available, so fetch it from there. Signed-off-by: David S. Miller --- net/sctp/protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4f270ac..4de77cb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -566,7 +566,7 @@ static void sctp_v4_get_saddr(struct sctp_sock *sk, if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr; } } -- cgit v1.1 From 517aa0bcda9b092a4c3fab7bf93f0cebe372ece0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 12 May 2011 11:27:20 +0000 Subject: sctp: sctp_sendmsg: Don't initialize default_sinfo This variable only needs initialization when cmsgs.info is NULL. Use memset to ensure padding is also zeroed so kernel doesn't leak any data. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/sctp/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/sctp') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 33d9ee6..d4b8db1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1496,7 +1496,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct sctp_chunk *chunk; union sctp_addr to; struct sockaddr *msg_name = NULL; - struct sctp_sndrcvinfo default_sinfo = { 0 }; + struct sctp_sndrcvinfo default_sinfo; struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; @@ -1760,6 +1760,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* If the user didn't specify SNDRCVINFO, make up one with * some defaults. */ + memset(&default_sinfo, 0, sizeof(default_sinfo)); default_sinfo.sinfo_stream = asoc->default_stream; default_sinfo.sinfo_flags = asoc->default_flags; default_sinfo.sinfo_ppid = asoc->default_ppid; -- cgit v1.1 From afd7614c00e364f8f1327e73ad291b02f6d4d1a6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 12 May 2011 09:19:10 +0000 Subject: sctp: sctp_sendmsg: Don't test known non-null sinfo It's already known non-null above. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/sctp/socket.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d4b8db1..6766913 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1791,12 +1791,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_free; } - if (sinfo) { - /* Check for invalid stream. */ - if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { - err = -EINVAL; - goto out_free; - } + /* Check for invalid stream. */ + if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { + err = -EINVAL; + goto out_free; } timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); -- cgit v1.1 From c182f90bc1f22ce5039b8722e45621d5f96862c2 Mon Sep 17 00:00:00 2001 From: Jacek Luczak Date: Thu, 19 May 2011 09:55:13 +0000 Subject: SCTP: fix race between sctp_bind_addr_free() and sctp_bind_addr_conflict() During the sctp_close() call, we do not use rcu primitives to destroy the address list attached to the endpoint. At the same time, we do the removal of addresses from this list before attempting to remove the socket from the port hash As a result, it is possible for another process to find the socket in the port hash that is in the process of being closed. It then proceeds to traverse the address list to find the conflict, only to have that address list suddenly disappear without rcu() critical section. Fix issue by closing address list removal inside RCU critical section. Race can result in a kernel crash with general protection fault or kernel NULL pointer dereference: kernel: general protection fault: 0000 [#1] SMP kernel: RIP: 0010:[] [] sctp_bind_addr_conflict+0x64/0x82 [sctp] kernel: Call Trace: kernel: [] ? sctp_get_port_local+0x17b/0x2a3 [sctp] kernel: [] ? sctp_bind_addr_match+0x33/0x68 [sctp] kernel: [] ? sctp_do_bind+0xd3/0x141 [sctp] kernel: [] ? sctp_bindx_add+0x4d/0x8e [sctp] kernel: [] ? sctp_setsockopt_bindx+0x112/0x4a4 [sctp] kernel: [] ? generic_file_aio_write+0x7f/0x9b kernel: [] ? sctp_setsockopt+0x14f/0xfee [sctp] kernel: [] ? do_sync_write+0xab/0xeb kernel: [] ? fsnotify+0x239/0x282 kernel: [] ? alloc_file+0x18/0xb1 kernel: [] ? compat_sys_setsockopt+0x1a5/0x1d9 kernel: [] ? compat_sys_socketcall+0x143/0x1a4 kernel: [] ? sysenter_dispatch+0x7/0x32 Signed-off-by: Jacek Luczak Acked-by: Vlad Yasevich CC: Eric Dumazet Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/bind_addr.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net/sctp') diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index faf71d1..6150ac5 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -140,14 +140,12 @@ void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) /* Dispose of the address list. */ static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { - struct sctp_sockaddr_entry *addr; - struct list_head *pos, *temp; + struct sctp_sockaddr_entry *addr, *temp; /* Empty the bind address list. */ - list_for_each_safe(pos, temp, &bp->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); - list_del(pos); - kfree(addr); + list_for_each_entry_safe(addr, temp, &bp->address_list, list) { + list_del_rcu(&addr->list); + call_rcu(&addr->rcu, sctp_local_addr_free); SCTP_DBG_OBJCNT_DEC(addr); } } -- cgit v1.1