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

📄 sm_make_chunk.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
struct sctp_chunk *sctp_make_abort_no_data(	const struct sctp_association *asoc,	const struct sctp_chunk *chunk, __u32 tsn){	struct sctp_chunk *retval;	__be32 payload;	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t)				 + sizeof(tsn));	if (!retval)		goto no_mem;	/* Put the tsn back into network byte order.  */	payload = htonl(tsn);	sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload));	sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload);	/* RFC 2960 6.4 Multi-homed SCTP Endpoints	 *	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,	 * HEARTBEAT ACK, * etc.) to the same destination transport	 * address from which it * received the DATA or control chunk	 * to which it is replying.	 *	 * [ABORT back to where the offender came from.]	 */	if (chunk)		retval->transport = chunk->transport;no_mem:	return retval;}/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,					const struct msghdr *msg,					size_t paylen){	struct sctp_chunk *retval;	void *payload = NULL;	int err;	retval = sctp_make_abort(asoc, NULL, sizeof(sctp_errhdr_t) + paylen);	if (!retval)		goto err_chunk;	if (paylen) {		/* Put the msg_iov together into payload.  */		payload = kmalloc(paylen, GFP_KERNEL);		if (!payload)			goto err_payload;		err = memcpy_fromiovec(payload, msg->msg_iov, paylen);		if (err < 0)			goto err_copy;	}	sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen);	sctp_addto_chunk(retval, paylen, payload);	if (paylen)		kfree(payload);	return retval;err_copy:	kfree(payload);err_payload:	sctp_chunk_free(retval);	retval = NULL;err_chunk:	return retval;}/* Append bytes to the end of a parameter.  Will panic if chunk is not big * enough. */static void *sctp_addto_param(struct sctp_chunk *chunk, int len,			      const void *data){	void *target;	int chunklen = ntohs(chunk->chunk_hdr->length);	target = skb_put(chunk->skb, len);	memcpy(target, data, len);	/* Adjust the chunk length field.  */	chunk->chunk_hdr->length = htons(chunklen + len);	chunk->chunk_end = skb_tail_pointer(chunk->skb);	return target;}/* 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_paramhdr_t));	if (!retval)		goto end;	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen					+ sizeof(sctp_paramhdr_t));	phdr.type = htons(chunk->chunk_hdr->type);	phdr.length = chunk->chunk_hdr->length;	sctp_addto_chunk(retval, paylen, payload);	sctp_addto_param(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,				  const void *payload, const size_t paylen){	struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,						    0, paylen);	if (!retval)		goto nodata;	/* 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);nodata:	return retval;}struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,				      const struct sctp_chunk *chunk,				      const void *payload, const size_t paylen){	struct sctp_chunk *retval;	retval  = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);	if (!retval)		goto nodata;	retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);	/* RFC 2960 6.4 Multi-homed SCTP Endpoints	 *	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,	 * HEARTBEAT ACK, * etc.) to the same destination transport	 * address from which it * received the DATA or control chunk	 * to which it is replying.	 *	 * [HBACK back to where the HEARTBEAT came from.]	 */	if (chunk)		retval->transport = chunk->transport;nodata:	return retval;}/* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */static struct sctp_chunk *sctp_make_op_error_space(	const struct sctp_association *asoc,	const struct sctp_chunk *chunk,	size_t size){	struct sctp_chunk *retval;	retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0,				 sizeof(sctp_errhdr_t) + size);	if (!retval)		goto nodata;	/* RFC 2960 6.4 Multi-homed SCTP Endpoints	 *	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,	 * HEARTBEAT ACK, etc.) to the same destination transport	 * address from which it received the DATA or control chunk	 * to which it is replying.	 *	 */	if (chunk)		retval->transport = chunk->transport;nodata:	return retval;}/* Create an Operation Error chunk.  */struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,				 const struct sctp_chunk *chunk,				 __be16 cause_code, const void *payload,				 size_t paylen){	struct sctp_chunk *retval;	retval = sctp_make_op_error_space(asoc, chunk, paylen);	if (!retval)		goto nodata;	sctp_init_cause(retval, cause_code, paylen);	sctp_addto_chunk(retval, paylen, payload);nodata:	return retval;}struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc){	struct sctp_chunk *retval;	struct sctp_hmac *hmac_desc;	struct sctp_authhdr auth_hdr;	__u8 *hmac;	/* Get the first hmac that the peer told us to use */	hmac_desc = sctp_auth_asoc_get_hmac(asoc);	if (unlikely(!hmac_desc))		return NULL;	retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0,			hmac_desc->hmac_len + sizeof(sctp_authhdr_t));	if (!retval)		return NULL;	auth_hdr.hmac_id = htons(hmac_desc->hmac_id);	auth_hdr.shkey_id = htons(asoc->active_key_id);	retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(sctp_authhdr_t),						&auth_hdr);	hmac = skb_put(retval->skb, hmac_desc->hmac_len);	memset(hmac, 0, hmac_desc->hmac_len);	/* Adjust the chunk header to include the empty MAC */	retval->chunk_hdr->length =		htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len);	retval->chunk_end = skb_tail_pointer(retval->skb);	return retval;}/******************************************************************** * 2nd Level Abstractions ********************************************************************//* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,			    const struct sctp_association *asoc,			    struct sock *sk){	struct sctp_chunk *retval;	retval = kmem_cache_zalloc(sctp_chunk_cachep, GFP_ATOMIC);	if (!retval)		goto nodata;	if (!sk) {		SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);	}	INIT_LIST_HEAD(&retval->list);	retval->skb		= skb;	retval->asoc		= (struct sctp_association *)asoc;	retval->resent  	= 0;	retval->has_tsn		= 0;	retval->has_ssn         = 0;	retval->rtt_in_progress	= 0;	retval->sent_at		= 0;	retval->singleton	= 1;	retval->end_of_packet	= 0;	retval->ecn_ce_done	= 0;	retval->pdiscard	= 0;	/* sctpimpguide-05.txt Section 2.8.2	 * M1) Each time a new DATA chunk is transmitted	 * set the 'TSN.Missing.Report' count for that TSN to 0. The	 * 'TSN.Missing.Report' count will be used to determine missing chunks	 * and when to fast retransmit.	 */	retval->tsn_missing_report = 0;	retval->tsn_gap_acked = 0;	retval->fast_retransmit = 0;	/* If this is a fragmented message, track all fragments	 * of the message (for SEND_FAILED).	 */	retval->msg = NULL;	/* Polish the bead hole.  */	INIT_LIST_HEAD(&retval->transmitted_list);	INIT_LIST_HEAD(&retval->frag_list);	SCTP_DBG_OBJCNT_INC(chunk);	atomic_set(&retval->refcnt, 1);nodata:	return retval;}/* Set chunk->source and dest based on the IP header in chunk->skb.  */void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src,		     union sctp_addr *dest){	memcpy(&chunk->source, src, sizeof(union sctp_addr));	memcpy(&chunk->dest, dest, sizeof(union sctp_addr));}/* Extract the source address from a chunk.  */const union sctp_addr *sctp_source(const struct sctp_chunk *chunk){	/* If we have a known transport, use that.  */	if (chunk->transport) {		return &chunk->transport->ipaddr;	} else {		/* Otherwise, extract it from the IP header.  */		return &chunk->source;	}}/* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */SCTP_STATICstruct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,				   __u8 type, __u8 flags, int paylen){	struct sctp_chunk *retval;	sctp_chunkhdr_t *chunk_hdr;	struct sk_buff *skb;	struct sock *sk;	/* No need to allocate LL here, as this is only a chunk. */	skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),			GFP_ATOMIC);	if (!skb)		goto nodata;	/* Make room for the chunk header.  */	chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t));	chunk_hdr->type	  = type;	chunk_hdr->flags  = flags;	chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));	sk = asoc ? asoc->base.sk : NULL;	retval = sctp_chunkify(skb, asoc, sk);	if (!retval) {		kfree_skb(skb);		goto nodata;	}	retval->chunk_hdr = chunk_hdr;	retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr);	/* Determine if the chunk needs to be authenticated */	if (sctp_auth_send_cid(type, asoc))		retval->auth = 1;	/* Set the skb to the belonging sock for accounting.  */	skb->sk = sk;	return retval;nodata:	return NULL;}/* Release the memory occupied by a chunk.  */static void sctp_chunk_destroy(struct sctp_chunk *chunk){	BUG_ON(!list_empty(&chunk->list));	list_del_init(&chunk->transmitted_list);	/* Free the chunk skb data and the SCTP_chunk stub itself. */	dev_kfree_skb(chunk->skb);	SCTP_DBG_OBJCNT_DEC(chunk);	kmem_cache_free(sctp_chunk_cachep, chunk);}/* Possibly, free the chunk.  */void sctp_chunk_free(struct sctp_chunk *chunk){	/* Release our reference on the message tracker. */	if (chunk->msg)		sctp_datamsg_put(chunk->msg);	sctp_chunk_put(chunk);}/* Grab a reference to the chunk. */void sctp_chunk_hold(struct sctp_chunk *ch){	atomic_inc(&ch->refcnt);}/* Release a reference to the chunk. */void sctp_chunk_put(struct sctp_chunk *ch){	if (atomic_dec_and_test(&ch->refcnt))		sctp_chunk_destroy(ch);}/* Append bytes to the end of a chunk.  Will panic if chunk is not big * enough. */void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data){	void *target;	void *padding;	int chunklen = ntohs(chunk->chunk_hdr->length);	int padlen = WORD_ROUND(chunklen) - chunklen;	padding = skb_put(chunk->skb, padlen);	target = skb_put(chunk->skb, len);	memset(padding, 0, padlen);	memcpy(target, data, len);	/* Adjust the chunk length field.  */	chunk->chunk_hdr->length = htons(chunklen + padlen + len);	chunk->chunk_end = skb_tail_pointer(chunk->skb);	return target;}/* Append bytes from user space to the end of a chunk.  Will panic if * chunk is not big enough. * Returns a kernel err value. */int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,

⌨️ 快捷键说明

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