extern kmem_cache_t *sctp_chunk_cachep;
+SCTP_STATIC
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
+ __u8 type, __u8 flags, int paylen);
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ const struct sctp_chunk *init_chunk,
+ int *cookie_len,
+ const __u8 *raw_addrs, int addrs_len);
+static int sctp_process_param(struct sctp_association *asoc,
+ union sctp_params param,
+ const union sctp_addr *peer_addr,
+ int gfp);
+
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
{
size_t chunksize;
struct sctp_chunk *retval = NULL;
int num_types, addrs_len = 0;
- struct sctp_opt *sp;
+ struct sctp_sock *sp;
sctp_supported_addrs_param_t sat;
__u16 types[2];
+ sctp_adaption_ind_param_t aiparam;
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
chunksize += sizeof(ecap_param);
if (sctp_prsctp_enable)
chunksize += sizeof(prsctp_param);
+ chunksize += sizeof(aiparam);
chunksize += vparam_len;
/* RFC 2960 3.3.2 Initiation (INIT) (1)
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
if (sctp_prsctp_enable)
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
+ aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND;
+ aiparam.param_hdr.length = htons(sizeof(aiparam));
+ aiparam.adaption_ind = htonl(sp->adaption_ind);
+ sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
nodata:
if (addrs.v)
kfree(addrs.v);
sctp_cookie_param_t *cookie;
int cookie_len;
size_t chunksize;
+ sctp_adaption_ind_param_t aiparam;
retval = NULL;
if (asoc->peer.prsctp_capable)
chunksize += sizeof(prsctp_param);
+ chunksize += sizeof(aiparam);
+
/* Now allocate and fill out the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
if (!retval)
if (asoc->peer.prsctp_capable)
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
+ aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND;
+ aiparam.param_hdr.length = htons(sizeof(aiparam));
+ aiparam.adaption_ind = htonl(sctp_sk(asoc->base.sk)->adaption_ind);
+ sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+
/* We need to remove the const qualifier at this point. */
retval->asoc = (struct sctp_association *) asoc;
return retval;
}
-/* Make a DATA chunk for the given association. Populate the data
- * payload.
- */
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
- const struct sctp_sndrcvinfo *sinfo,
- int data_len, const __u8 *data,
- __u8 flags, __u16 ssn)
-{
- struct sctp_chunk *retval;
-
- retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
- if (retval)
- sctp_addto_chunk(retval, data_len, data);
-
- return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body of 'data'.
- */
-struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
- const struct sctp_sndrcvinfo *sinfo,
- int data_len, const __u8 *data)
-{
- struct sctp_chunk *retval = NULL;
-
- retval = sctp_make_data_empty(asoc, sinfo, data_len);
- if (retval)
- sctp_addto_chunk(retval, data_len, data);
- return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body big enough to
- * hold 'data_len' octets of data. We use this version when we need
- * to build the message AFTER allocating memory.
- */
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
- const struct sctp_sndrcvinfo *sinfo,
- int data_len)
-{
- __u8 flags = SCTP_DATA_NOT_FRAG;
-
- return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
-}
-
/* Create a selective ackowledgement (SACK) for the given
* association. This reports on which TSN's we've seen to date,
* including duplicates and gaps.
return retval;
}
+/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */
+struct sctp_chunk *sctp_make_abort_violation(
+ const struct sctp_association *asoc,
+ const struct sctp_chunk *chunk,
+ const __u8 *payload,
+ const size_t paylen)
+{
+ struct sctp_chunk *retval;
+ struct sctp_paramhdr phdr;
+
+ retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+ + sizeof(sctp_chunkhdr_t));
+ if (!retval)
+ goto end;
+
+ sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
+
+ phdr.type = htons(chunk->chunk_hdr->type);
+ phdr.length = chunk->chunk_hdr->length;
+ sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
+
+end:
+ return retval;
+}
+
/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport,
/* Create an Operation Error chunk with the specified space reserved.
* This routine can be used for containing multiple causes in the chunk.
*/
-struct sctp_chunk *sctp_make_op_error_space(
+static struct sctp_chunk *sctp_make_op_error_space(
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
size_t size)
SCTP_DBG_OBJCNT_INC(chunk);
atomic_set(&retval->refcnt, 1);
-
nodata:
return retval;
}
/* Create a new chunk, setting the type and flags headers from the
* arguments, reserving enough space for a 'paylen' byte payload.
*/
+SCTP_STATIC
struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen)
{
/* Build a cookie representing asoc.
* This INCLUDES the param header needed to put the cookie in the INIT ACK.
*/
-sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *init_chunk,
int *cookie_len,
/* Remember PR-SCTP capability. */
cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
+ /* Save adaption indication in the cookie. */
+ cookie->c.adaption_ind = asoc->peer.adaption_ind;
+
/* Set an expiration time for the cookie. */
do_gettimeofday(&cookie->c.expiration);
TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);
}
no_hmac:
+ /* IG Section 2.35.2:
+ * 3) Compare the port numbers and the verification tag contained
+ * within the COOKIE ECHO chunk to the actual port numbers and the
+ * verification tag within the SCTP common header of the received
+ * packet. If these values do not match the packet MUST be silently
+ * discarded,
+ */
+ if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
+ *error = -SCTP_IERROR_BAD_TAG;
+ goto fail;
+ }
+
+ if (ntohs(chunk->sctp_hdr->source) != bear_cookie->peer_addr.v4.sin_port ||
+ ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
+ *error = -SCTP_IERROR_BAD_PORTS;
+ goto fail;
+ }
+
/* Check to see if the cookie is stale. If there is already
* an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK.
retval->addip_serial = retval->c.initial_tsn;
retval->adv_peer_ack_point = retval->ctsn_ack_point;
retval->peer.prsctp_capable = retval->c.prsctp_capable;
+ retval->peer.adaption_ind = retval->c.adaption_ind;
/* The INIT stuff will be done by the side effects. */
return retval;
return 0;
}
+static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
+ struct sctp_paramhdr *param,
+ const struct sctp_chunk *chunk,
+ struct sctp_chunk **errp)
+{
+ char error[] = "The following parameter had invalid length:";
+ size_t payload_len = WORD_ROUND(sizeof(error)) +
+ sizeof(sctp_paramhdr_t);
+
+
+ /* Create an error chunk and fill it in with our payload. */
+ if (!*errp)
+ *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+
+ if (*errp) {
+ sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
+ sizeof(error));
+ sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
+ }
+
+ return 0;
+}
+
+
/* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer.
*/
case SCTP_PARAM_HEARTBEAT_INFO:
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
+ case SCTP_PARAM_ADAPTION_LAYER_IND:
break;
case SCTP_PARAM_HOST_NAME_ADDRESS:
} /* for (loop through all parameters) */
+ /* There is a possibility that a parameter length was bad and
+ * in that case we would have stoped walking the parameters.
+ * The current param.p would point at the bad one.
+ * Current consensus on the mailing list is to generate a PROTOCOL
+ * VIOLATION error. We build the ERROR chunk here and let the normal
+ * error handling code build and send the packet.
+ */
+ if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
+ sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
+ return 0;
+ }
+
/* The only missing mandatory param possible today is
* the state cookie for an INIT-ACK chunk.
*/
* work we do. In particular, we should not build transport
* structures for the addresses.
*/
-int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
- const union sctp_addr *peer_addr, int gfp)
+static int sctp_process_param(struct sctp_association *asoc,
+ union sctp_params param,
+ const union sctp_addr *peer_addr,
+ int gfp)
{
union sctp_addr addr;
int i;
asoc->peer.ecn_capable = 1;
break;
+ case SCTP_PARAM_ADAPTION_LAYER_IND:
+ asoc->peer.adaption_ind = param.aind->adaption_ind;
+ break;
+
case SCTP_PARAM_FWD_TSN_SUPPORT:
if (sctp_prsctp_enable) {
asoc->peer.prsctp_capable = 1;
*
* Address Parameter and other parameter will not be wrapped in this function
*/
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
- union sctp_addr *addr, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
+ union sctp_addr *addr,
+ int vparam_len)
{
sctp_addiphdr_t asconf;
struct sctp_chunk *retval;
*
* Create an ASCONF_ACK chunk with enough space for the parameter responses.
*/
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
- __u32 serial, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
+ __u32 serial, int vparam_len)
{
sctp_addiphdr_t asconf;
struct sctp_chunk *retval;
union sctp_addr addr;
struct sctp_bind_addr *bp = &asoc->base.bind_addr;
union sctp_addr_param *addr_param;
+ struct list_head *pos;
+ struct sctp_transport *transport;
int retval = 0;
addr_param = (union sctp_addr_param *)
retval = sctp_del_bind_addr(bp, &addr);
sctp_write_unlock(&asoc->base.addr_lock);
sctp_local_bh_enable();
+ list_for_each(pos, &asoc->peer.transport_addr_list) {
+ transport = list_entry(pos, struct sctp_transport,
+ transports);
+ sctp_transport_route(transport, NULL,
+ sctp_sk(asoc->base.sk));
+ }
break;
default:
break;