diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 6 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 1 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 94 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 26 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 8 | ||||
-rw-r--r-- | net/sctp/socket.c | 17 |
6 files changed, 120 insertions, 32 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index df5abbff63e2..99c93ee98ad9 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -1194,8 +1194,10 @@ void sctp_assoc_update(struct sctp_association *asoc, | |||
1194 | /* Remove any peer addresses not present in the new association. */ | 1194 | /* Remove any peer addresses not present in the new association. */ |
1195 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { | 1195 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { |
1196 | trans = list_entry(pos, struct sctp_transport, transports); | 1196 | trans = list_entry(pos, struct sctp_transport, transports); |
1197 | if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) | 1197 | if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) { |
1198 | sctp_assoc_del_peer(asoc, &trans->ipaddr); | 1198 | sctp_assoc_rm_peer(asoc, trans); |
1199 | continue; | ||
1200 | } | ||
1199 | 1201 | ||
1200 | if (asoc->state >= SCTP_STATE_ESTABLISHED) | 1202 | if (asoc->state >= SCTP_STATE_ESTABLISHED) |
1201 | sctp_transport_reset(trans); | 1203 | sctp_transport_reset(trans); |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 905fda582b92..7ec09ba03a1c 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -144,6 +144,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, | |||
144 | /* Use SCTP specific send buffer space queues. */ | 144 | /* Use SCTP specific send buffer space queues. */ |
145 | ep->sndbuf_policy = sctp_sndbuf_policy; | 145 | ep->sndbuf_policy = sctp_sndbuf_policy; |
146 | 146 | ||
147 | sk->sk_data_ready = sctp_data_ready; | ||
147 | sk->sk_write_space = sctp_write_space; | 148 | sk->sk_write_space = sctp_write_space; |
148 | sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); | 149 | sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); |
149 | 150 | ||
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 17cb400ecd6a..30c1767186b8 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -108,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = { | |||
108 | cpu_to_be16(sizeof(struct sctp_paramhdr)), | 108 | cpu_to_be16(sizeof(struct sctp_paramhdr)), |
109 | }; | 109 | }; |
110 | 110 | ||
111 | /* A helper to initialize to initialize an op error inside a | 111 | /* A helper to initialize an op error inside a |
112 | * provided chunk, as most cause codes will be embedded inside an | 112 | * provided chunk, as most cause codes will be embedded inside an |
113 | * abort chunk. | 113 | * abort chunk. |
114 | */ | 114 | */ |
@@ -125,6 +125,29 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, | |||
125 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); | 125 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* A helper to initialize an op error inside a | ||
129 | * provided chunk, as most cause codes will be embedded inside an | ||
130 | * abort chunk. Differs from sctp_init_cause in that it won't oops | ||
131 | * if there isn't enough space in the op error chunk | ||
132 | */ | ||
133 | int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code, | ||
134 | size_t paylen) | ||
135 | { | ||
136 | sctp_errhdr_t err; | ||
137 | __u16 len; | ||
138 | |||
139 | /* Cause code constants are now defined in network order. */ | ||
140 | err.cause = cause_code; | ||
141 | len = sizeof(sctp_errhdr_t) + paylen; | ||
142 | err.length = htons(len); | ||
143 | |||
144 | if (skb_tailroom(chunk->skb) > len) | ||
145 | return -ENOSPC; | ||
146 | chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk, | ||
147 | sizeof(sctp_errhdr_t), | ||
148 | &err); | ||
149 | return 0; | ||
150 | } | ||
128 | /* 3.3.2 Initiation (INIT) (1) | 151 | /* 3.3.2 Initiation (INIT) (1) |
129 | * | 152 | * |
130 | * This chunk is used to initiate a SCTP association between two | 153 | * This chunk is used to initiate a SCTP association between two |
@@ -208,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
208 | sp = sctp_sk(asoc->base.sk); | 231 | sp = sctp_sk(asoc->base.sk); |
209 | num_types = sp->pf->supported_addrs(sp, types); | 232 | num_types = sp->pf->supported_addrs(sp, types); |
210 | 233 | ||
211 | chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); | 234 | chunksize = sizeof(init) + addrs_len; |
235 | chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types)); | ||
212 | chunksize += sizeof(ecap_param); | 236 | chunksize += sizeof(ecap_param); |
213 | 237 | ||
214 | if (sctp_prsctp_enable) | 238 | if (sctp_prsctp_enable) |
@@ -238,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
238 | /* Add HMACS parameter length if any were defined */ | 262 | /* Add HMACS parameter length if any were defined */ |
239 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; | 263 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; |
240 | if (auth_hmacs->length) | 264 | if (auth_hmacs->length) |
241 | chunksize += ntohs(auth_hmacs->length); | 265 | chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); |
242 | else | 266 | else |
243 | auth_hmacs = NULL; | 267 | auth_hmacs = NULL; |
244 | 268 | ||
245 | /* Add CHUNKS parameter length */ | 269 | /* Add CHUNKS parameter length */ |
246 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; | 270 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; |
247 | if (auth_chunks->length) | 271 | if (auth_chunks->length) |
248 | chunksize += ntohs(auth_chunks->length); | 272 | chunksize += WORD_ROUND(ntohs(auth_chunks->length)); |
249 | else | 273 | else |
250 | auth_chunks = NULL; | 274 | auth_chunks = NULL; |
251 | 275 | ||
@@ -255,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
255 | 279 | ||
256 | /* If we have any extensions to report, account for that */ | 280 | /* If we have any extensions to report, account for that */ |
257 | if (num_ext) | 281 | if (num_ext) |
258 | chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; | 282 | chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + |
283 | num_ext); | ||
259 | 284 | ||
260 | /* RFC 2960 3.3.2 Initiation (INIT) (1) | 285 | /* RFC 2960 3.3.2 Initiation (INIT) (1) |
261 | * | 286 | * |
@@ -397,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
397 | 422 | ||
398 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; | 423 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; |
399 | if (auth_hmacs->length) | 424 | if (auth_hmacs->length) |
400 | chunksize += ntohs(auth_hmacs->length); | 425 | chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); |
401 | else | 426 | else |
402 | auth_hmacs = NULL; | 427 | auth_hmacs = NULL; |
403 | 428 | ||
404 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; | 429 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; |
405 | if (auth_chunks->length) | 430 | if (auth_chunks->length) |
406 | chunksize += ntohs(auth_chunks->length); | 431 | chunksize += WORD_ROUND(ntohs(auth_chunks->length)); |
407 | else | 432 | else |
408 | auth_chunks = NULL; | 433 | auth_chunks = NULL; |
409 | 434 | ||
@@ -412,7 +437,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
412 | } | 437 | } |
413 | 438 | ||
414 | if (num_ext) | 439 | if (num_ext) |
415 | chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; | 440 | chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + |
441 | num_ext); | ||
416 | 442 | ||
417 | /* Now allocate and fill out the chunk. */ | 443 | /* Now allocate and fill out the chunk. */ |
418 | retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); | 444 | retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); |
@@ -1129,6 +1155,24 @@ nodata: | |||
1129 | return retval; | 1155 | return retval; |
1130 | } | 1156 | } |
1131 | 1157 | ||
1158 | /* Create an Operation Error chunk of a fixed size, | ||
1159 | * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) | ||
1160 | * This is a helper function to allocate an error chunk for | ||
1161 | * for those invalid parameter codes in which we may not want | ||
1162 | * to report all the errors, if the incomming chunk is large | ||
1163 | */ | ||
1164 | static inline struct sctp_chunk *sctp_make_op_error_fixed( | ||
1165 | const struct sctp_association *asoc, | ||
1166 | const struct sctp_chunk *chunk) | ||
1167 | { | ||
1168 | size_t size = asoc ? asoc->pathmtu : 0; | ||
1169 | |||
1170 | if (!size) | ||
1171 | size = SCTP_DEFAULT_MAXSEGMENT; | ||
1172 | |||
1173 | return sctp_make_op_error_space(asoc, chunk, size); | ||
1174 | } | ||
1175 | |||
1132 | /* Create an Operation Error chunk. */ | 1176 | /* Create an Operation Error chunk. */ |
1133 | struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, | 1177 | struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, |
1134 | const struct sctp_chunk *chunk, | 1178 | const struct sctp_chunk *chunk, |
@@ -1371,6 +1415,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
1371 | return target; | 1415 | return target; |
1372 | } | 1416 | } |
1373 | 1417 | ||
1418 | /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient | ||
1419 | * space in the chunk | ||
1420 | */ | ||
1421 | void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, | ||
1422 | int len, const void *data) | ||
1423 | { | ||
1424 | if (skb_tailroom(chunk->skb) > len) | ||
1425 | return sctp_addto_chunk(chunk, len, data); | ||
1426 | else | ||
1427 | return NULL; | ||
1428 | } | ||
1429 | |||
1374 | /* Append bytes from user space to the end of a chunk. Will panic if | 1430 | /* Append bytes from user space to the end of a chunk. Will panic if |
1375 | * chunk is not big enough. | 1431 | * chunk is not big enough. |
1376 | * Returns a kernel err value. | 1432 | * Returns a kernel err value. |
@@ -1974,13 +2030,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, | |||
1974 | * returning multiple unknown parameters. | 2030 | * returning multiple unknown parameters. |
1975 | */ | 2031 | */ |
1976 | if (NULL == *errp) | 2032 | if (NULL == *errp) |
1977 | *errp = sctp_make_op_error_space(asoc, chunk, | 2033 | *errp = sctp_make_op_error_fixed(asoc, chunk); |
1978 | ntohs(chunk->chunk_hdr->length)); | ||
1979 | 2034 | ||
1980 | if (*errp) { | 2035 | if (*errp) { |
1981 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | 2036 | sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, |
1982 | WORD_ROUND(ntohs(param.p->length))); | 2037 | WORD_ROUND(ntohs(param.p->length))); |
1983 | sctp_addto_chunk(*errp, | 2038 | sctp_addto_chunk_fixed(*errp, |
1984 | WORD_ROUND(ntohs(param.p->length)), | 2039 | WORD_ROUND(ntohs(param.p->length)), |
1985 | param.v); | 2040 | param.v); |
1986 | } else { | 2041 | } else { |
@@ -3315,21 +3370,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, | |||
3315 | sctp_chunk_free(asconf); | 3370 | sctp_chunk_free(asconf); |
3316 | asoc->addip_last_asconf = NULL; | 3371 | asoc->addip_last_asconf = NULL; |
3317 | 3372 | ||
3318 | /* Send the next asconf chunk from the addip chunk queue. */ | ||
3319 | if (!list_empty(&asoc->addip_chunk_list)) { | ||
3320 | struct list_head *entry = asoc->addip_chunk_list.next; | ||
3321 | asconf = list_entry(entry, struct sctp_chunk, list); | ||
3322 | |||
3323 | list_del_init(entry); | ||
3324 | |||
3325 | /* Hold the chunk until an ASCONF_ACK is received. */ | ||
3326 | sctp_chunk_hold(asconf); | ||
3327 | if (sctp_primitive_ASCONF(asoc, asconf)) | ||
3328 | sctp_chunk_free(asconf); | ||
3329 | else | ||
3330 | asoc->addip_last_asconf = asconf; | ||
3331 | } | ||
3332 | |||
3333 | return retval; | 3373 | return retval; |
3334 | } | 3374 | } |
3335 | 3375 | ||
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 4c5bed9af4e3..d5ae450b6f02 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -962,6 +962,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc, | |||
962 | } | 962 | } |
963 | 963 | ||
964 | 964 | ||
965 | /* Sent the next ASCONF packet currently stored in the association. | ||
966 | * This happens after the ASCONF_ACK was succeffully processed. | ||
967 | */ | ||
968 | static void sctp_cmd_send_asconf(struct sctp_association *asoc) | ||
969 | { | ||
970 | /* Send the next asconf chunk from the addip chunk | ||
971 | * queue. | ||
972 | */ | ||
973 | if (!list_empty(&asoc->addip_chunk_list)) { | ||
974 | struct list_head *entry = asoc->addip_chunk_list.next; | ||
975 | struct sctp_chunk *asconf = list_entry(entry, | ||
976 | struct sctp_chunk, list); | ||
977 | list_del_init(entry); | ||
978 | |||
979 | /* Hold the chunk until an ASCONF_ACK is received. */ | ||
980 | sctp_chunk_hold(asconf); | ||
981 | if (sctp_primitive_ASCONF(asoc, asconf)) | ||
982 | sctp_chunk_free(asconf); | ||
983 | else | ||
984 | asoc->addip_last_asconf = asconf; | ||
985 | } | ||
986 | } | ||
987 | |||
965 | 988 | ||
966 | /* These three macros allow us to pull the debugging code out of the | 989 | /* These three macros allow us to pull the debugging code out of the |
967 | * main flow of sctp_do_sm() to keep attention focused on the real | 990 | * main flow of sctp_do_sm() to keep attention focused on the real |
@@ -1617,6 +1640,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1617 | } | 1640 | } |
1618 | error = sctp_cmd_send_msg(asoc, cmd->obj.msg); | 1641 | error = sctp_cmd_send_msg(asoc, cmd->obj.msg); |
1619 | break; | 1642 | break; |
1643 | case SCTP_CMD_SEND_NEXT_ASCONF: | ||
1644 | sctp_cmd_send_asconf(asoc); | ||
1645 | break; | ||
1620 | default: | 1646 | default: |
1621 | printk(KERN_WARNING "Impossible command: %u, %p\n", | 1647 | printk(KERN_WARNING "Impossible command: %u, %p\n", |
1622 | cmd->verb, cmd->obj.ptr); | 1648 | cmd->verb, cmd->obj.ptr); |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index abf601a1b847..24b2cd555637 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -3676,8 +3676,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, | |||
3676 | SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); | 3676 | SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); |
3677 | 3677 | ||
3678 | if (!sctp_process_asconf_ack((struct sctp_association *)asoc, | 3678 | if (!sctp_process_asconf_ack((struct sctp_association *)asoc, |
3679 | asconf_ack)) | 3679 | asconf_ack)) { |
3680 | /* Successfully processed ASCONF_ACK. We can | ||
3681 | * release the next asconf if we have one. | ||
3682 | */ | ||
3683 | sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF, | ||
3684 | SCTP_NULL()); | ||
3680 | return SCTP_DISPOSITION_CONSUME; | 3685 | return SCTP_DISPOSITION_CONSUME; |
3686 | } | ||
3681 | 3687 | ||
3682 | abort = sctp_make_abort(asoc, asconf_ack, | 3688 | abort = sctp_make_abort(asoc, asconf_ack, |
3683 | sizeof(sctp_errhdr_t)); | 3689 | sizeof(sctp_errhdr_t)); |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d54700af927a..bae764005d2d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -3719,9 +3719,9 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3719 | sp->hmac = NULL; | 3719 | sp->hmac = NULL; |
3720 | 3720 | ||
3721 | SCTP_DBG_OBJCNT_INC(sock); | 3721 | SCTP_DBG_OBJCNT_INC(sock); |
3722 | percpu_counter_inc(&sctp_sockets_allocated); | ||
3723 | 3722 | ||
3724 | local_bh_disable(); | 3723 | local_bh_disable(); |
3724 | percpu_counter_inc(&sctp_sockets_allocated); | ||
3725 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 3725 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
3726 | local_bh_enable(); | 3726 | local_bh_enable(); |
3727 | 3727 | ||
@@ -3738,8 +3738,8 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) | |||
3738 | /* Release our hold on the endpoint. */ | 3738 | /* Release our hold on the endpoint. */ |
3739 | ep = sctp_sk(sk)->ep; | 3739 | ep = sctp_sk(sk)->ep; |
3740 | sctp_endpoint_free(ep); | 3740 | sctp_endpoint_free(ep); |
3741 | percpu_counter_dec(&sctp_sockets_allocated); | ||
3742 | local_bh_disable(); | 3741 | local_bh_disable(); |
3742 | percpu_counter_dec(&sctp_sockets_allocated); | ||
3743 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 3743 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
3744 | local_bh_enable(); | 3744 | local_bh_enable(); |
3745 | } | 3745 | } |
@@ -6185,6 +6185,19 @@ do_nonblock: | |||
6185 | goto out; | 6185 | goto out; |
6186 | } | 6186 | } |
6187 | 6187 | ||
6188 | void sctp_data_ready(struct sock *sk, int len) | ||
6189 | { | ||
6190 | struct socket_wq *wq; | ||
6191 | |||
6192 | rcu_read_lock(); | ||
6193 | wq = rcu_dereference(sk->sk_wq); | ||
6194 | if (wq_has_sleeper(wq)) | ||
6195 | wake_up_interruptible_sync_poll(&wq->wait, POLLIN | | ||
6196 | POLLRDNORM | POLLRDBAND); | ||
6197 | sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); | ||
6198 | rcu_read_unlock(); | ||
6199 | } | ||
6200 | |||
6188 | /* If socket sndbuf has changed, wake up all per association waiters. */ | 6201 | /* If socket sndbuf has changed, wake up all per association waiters. */ |
6189 | void sctp_write_space(struct sock *sk) | 6202 | void sctp_write_space(struct sock *sk) |
6190 | { | 6203 | { |