⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sm_make_chunk.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			  struct iovec *data){	__u8 *target;	int err = 0;	/* Make room in chunk for data.  */	target = skb_put(chunk->skb, len);	/* Copy data (whole iovec) into chunk */	if ((err = memcpy_fromiovecend(target, data, off, len)))		goto out;	/* Adjust the chunk length field.  */	chunk->chunk_hdr->length =		htons(ntohs(chunk->chunk_hdr->length) + len);	chunk->chunk_end = skb_tail_pointer(chunk->skb);out:	return err;}/* Helper function to assign a TSN if needed.  This assumes that both * the data_hdr and association have already been assigned. */void sctp_chunk_assign_ssn(struct sctp_chunk *chunk){	struct sctp_datamsg *msg;	struct sctp_chunk *lchunk;	struct sctp_stream *stream;	__u16 ssn;	__u16 sid;	if (chunk->has_ssn)		return;	/* All fragments will be on the same stream */	sid = ntohs(chunk->subh.data_hdr->stream);	stream = &chunk->asoc->ssnmap->out;	/* Now assign the sequence number to the entire message.	 * All fragments must have the same stream sequence number.	 */	msg = chunk->msg;	list_for_each_entry(lchunk, &msg->chunks, frag_list) {		if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {			ssn = 0;		} else {			if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)				ssn = sctp_ssn_next(stream, sid);			else				ssn = sctp_ssn_peek(stream, sid);		}		lchunk->subh.data_hdr->ssn = htons(ssn);		lchunk->has_ssn = 1;	}}/* Helper function to assign a TSN if needed.  This assumes that both * the data_hdr and association have already been assigned. */void sctp_chunk_assign_tsn(struct sctp_chunk *chunk){	if (!chunk->has_tsn) {		/* This is the last possible instant to		 * assign a TSN.		 */		chunk->subh.data_hdr->tsn =			htonl(sctp_association_get_next_tsn(chunk->asoc));		chunk->has_tsn = 1;	}}/* Create a CLOSED association to use with an incoming packet.  */struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,					struct sctp_chunk *chunk,					gfp_t gfp){	struct sctp_association *asoc;	struct sk_buff *skb;	sctp_scope_t scope;	struct sctp_af *af;	/* Create the bare association.  */	scope = sctp_scope(sctp_source(chunk));	asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);	if (!asoc)		goto nodata;	asoc->temp = 1;	skb = chunk->skb;	/* Create an entry for the source address of the packet.  */	af = sctp_get_af_specific(ipver2af(ip_hdr(skb)->version));	if (unlikely(!af))		goto fail;	af->from_skb(&asoc->c.peer_addr, skb, 1);nodata:	return asoc;fail:	sctp_association_free(asoc);	return NULL;}/* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */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){	sctp_cookie_param_t *retval;	struct sctp_signed_cookie *cookie;	struct scatterlist sg;	int headersize, bodysize;	unsigned int keylen;	char *key;	/* Header size is static data prior to the actual cookie, including	 * any padding.	 */	headersize = sizeof(sctp_paramhdr_t) +		     (sizeof(struct sctp_signed_cookie) -		      sizeof(struct sctp_cookie));	bodysize = sizeof(struct sctp_cookie)		+ ntohs(init_chunk->chunk_hdr->length) + addrs_len;	/* Pad out the cookie to a multiple to make the signature	 * functions simpler to write.	 */	if (bodysize % SCTP_COOKIE_MULTIPLE)		bodysize += SCTP_COOKIE_MULTIPLE			- (bodysize % SCTP_COOKIE_MULTIPLE);	*cookie_len = headersize + bodysize;	/* Clear this memory since we are sending this data structure	 * out on the network.	 */	retval = kzalloc(*cookie_len, GFP_ATOMIC);	if (!retval)		goto nodata;	cookie = (struct sctp_signed_cookie *) retval->body;	/* Set up the parameter header.  */	retval->p.type = SCTP_PARAM_STATE_COOKIE;	retval->p.length = htons(*cookie_len);	/* Copy the cookie part of the association itself.  */	cookie->c = asoc->c;	/* Save the raw address list length in the cookie. */	cookie->c.raw_addr_list_len = addrs_len;	/* Remember PR-SCTP capability. */	cookie->c.prsctp_capable = asoc->peer.prsctp_capable;	/* Save adaptation indication in the cookie. */	cookie->c.adaptation_ind = asoc->peer.adaptation_ind;	/* Set an expiration time for the cookie.  */	do_gettimeofday(&cookie->c.expiration);	TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);	/* Copy the peer's init packet.  */	memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,	       ntohs(init_chunk->chunk_hdr->length));	/* Copy the raw local address list of the association. */	memcpy((__u8 *)&cookie->c.peer_init[0] +	       ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);	if (sctp_sk(ep->base.sk)->hmac) {		struct hash_desc desc;		/* Sign the message.  */		sg_init_one(&sg, &cookie->c, bodysize);		keylen = SCTP_SECRET_SIZE;		key = (char *)ep->secret_key[ep->current_key];		desc.tfm = sctp_sk(ep->base.sk)->hmac;		desc.flags = 0;		if (crypto_hash_setkey(desc.tfm, key, keylen) ||		    crypto_hash_digest(&desc, &sg, bodysize, cookie->signature))			goto free_cookie;	}	return retval;free_cookie:	kfree(retval);nodata:	*cookie_len = 0;	return NULL;}/* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */struct sctp_association *sctp_unpack_cookie(	const struct sctp_endpoint *ep,	const struct sctp_association *asoc,	struct sctp_chunk *chunk, gfp_t gfp,	int *error, struct sctp_chunk **errp){	struct sctp_association *retval = NULL;	struct sctp_signed_cookie *cookie;	struct sctp_cookie *bear_cookie;	int headersize, bodysize, fixed_size;	__u8 *digest = ep->digest;	struct scatterlist sg;	unsigned int keylen, len;	char *key;	sctp_scope_t scope;	struct sk_buff *skb = chunk->skb;	struct timeval tv;	struct hash_desc desc;	/* Header size is static data prior to the actual cookie, including	 * any padding.	 */	headersize = sizeof(sctp_chunkhdr_t) +		     (sizeof(struct sctp_signed_cookie) -		      sizeof(struct sctp_cookie));	bodysize = ntohs(chunk->chunk_hdr->length) - headersize;	fixed_size = headersize + sizeof(struct sctp_cookie);	/* Verify that the chunk looks like it even has a cookie.	 * There must be enough room for our cookie and our peer's	 * INIT chunk.	 */	len = ntohs(chunk->chunk_hdr->length);	if (len < fixed_size + sizeof(struct sctp_chunkhdr))		goto malformed;	/* Verify that the cookie has been padded out. */	if (bodysize % SCTP_COOKIE_MULTIPLE)		goto malformed;	/* Process the cookie.  */	cookie = chunk->subh.cookie_hdr;	bear_cookie = &cookie->c;	if (!sctp_sk(ep->base.sk)->hmac)		goto no_hmac;	/* Check the signature.  */	keylen = SCTP_SECRET_SIZE;	sg_init_one(&sg, bear_cookie, bodysize);	key = (char *)ep->secret_key[ep->current_key];	desc.tfm = sctp_sk(ep->base.sk)->hmac;	desc.flags = 0;	memset(digest, 0x00, SCTP_SIGNATURE_SIZE);	if (crypto_hash_setkey(desc.tfm, key, keylen) ||	    crypto_hash_digest(&desc, &sg, bodysize, digest)) {		*error = -SCTP_IERROR_NOMEM;		goto fail;	}	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {		/* Try the previous key. */		key = (char *)ep->secret_key[ep->last_key];		memset(digest, 0x00, SCTP_SIGNATURE_SIZE);		if (crypto_hash_setkey(desc.tfm, key, keylen) ||		    crypto_hash_digest(&desc, &sg, bodysize, digest)) {			*error = -SCTP_IERROR_NOMEM;			goto fail;		}		if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {			/* Yikes!  Still bad signature! */			*error = -SCTP_IERROR_BAD_SIG;			goto fail;		}	}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 (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.	 * If skb has been timestamped, then use the stamp, otherwise	 * use current time.  This introduces a small possibility that	 * that a cookie may be considered expired, but his would only slow	 * down the new association establishment instead of every packet.	 */	if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))		skb_get_timestamp(skb, &tv);	else		do_gettimeofday(&tv);	if (!asoc && tv_lt(bear_cookie->expiration, tv)) {		/*		 * Section 3.3.10.3 Stale Cookie Error (3)		 *		 * Cause of error		 * ---------------		 * Stale Cookie Error:  Indicates the receipt of a valid State		 * Cookie that has expired.		 */		len = ntohs(chunk->chunk_hdr->length);		*errp = sctp_make_op_error_space(asoc, chunk, len);		if (*errp) {			suseconds_t usecs = (tv.tv_sec -				bear_cookie->expiration.tv_sec) * 1000000L +				tv.tv_usec - bear_cookie->expiration.tv_usec;			__be32 n = htonl(usecs);			sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,					sizeof(n));			sctp_addto_chunk(*errp, sizeof(n), &n);			*error = -SCTP_IERROR_STALE_COOKIE;		} else			*error = -SCTP_IERROR_NOMEM;		goto fail;	}	/* Make a new base association.  */	scope = sctp_scope(sctp_source(chunk));	retval = sctp_association_new(ep, ep->base.sk, scope, gfp);	if (!retval) {		*error = -SCTP_IERROR_NOMEM;		goto fail;	}	/* Set up our peer's port number.  */	retval->peer.port = ntohs(chunk->sctp_hdr->source);	/* Populate the association from the cookie.  */	memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));	if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie,						 GFP_ATOMIC) < 0) {		*error = -SCTP_IERROR_NOMEM;		goto fail;	}	/* Also, add the destination address. */	if (list_empty(&retval->base.bind_addr.address_list)) {		sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,				SCTP_ADDR_SRC, GFP_ATOMIC);	}	retval->next_tsn = retval->c.initial_tsn;	retval->ctsn_ack_point = retval->next_tsn - 1;	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.adaptation_ind = retval->c.adaptation_ind;	/* The INIT stuff will be done by the side effects.  */	return retval;fail:	if (retval)		sctp_association_free(retval);	return NULL;malformed:	/* Yikes!  The packet is either corrupt or deliberately	 * malformed.	 */	*error = -SCTP_IERROR_MALFORMED;	goto fail;}/******************************************************************** * 3rd Level Abstractions ********************************************************************/struct __sctp_missing {	__be32 num_missing;	__be16 type;}  __attribute__((packed));/* * Report a missing mandatory parameter. */static int sctp_process_missing_param(const struct sctp_association *asoc,				      sctp_param_t paramtype,				      struct sctp_chunk *chunk,				      struct sctp_chunk **errp){	struct __sctp_missing report;	__u16 len;	len = WORD_ROUND(sizeof(report));	/* Make an ERROR chunk, preparing enough room for	 * returning multiple unknown parameters.	 */	if (!*errp)		*errp = sctp_make_op_error_space(asoc, chunk, len);	if (*errp) {		report.num_missing = htonl(1);		report.type = paramtype;		sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,				sizeof(report));		sctp_addto_chunk(*errp, sizeof(report), &report);	}	/* Stop processing this chunk. */	return 0;}/* Report an Invalid Mandatory Parameter.  */static int sctp_process_inv_mandatory(const struct sctp_association *asoc,				      struct sctp_chunk *chunk,				      struct sctp_chunk **errp){	/* Invalid Mandatory Parameter Error has no payload. */	if (!*errp)		*errp = sctp_make_op_error_space(asoc, chunk, 0);	if (*errp)		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0);	/* Stop processing this chunk. */	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){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -