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

📄 sm_make_chunk.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	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. */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,				 __u16 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, payload, paylen);nodata:	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_alloc(sctp_chunk_cachep, SLAB_ATOMIC);	if (!retval)		goto nodata;	memset(retval, 0, sizeof(struct sctp_chunk));	if (!sk) {		SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);	}	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. */struct 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);	/* 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){	/* 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){	/* Make sure that we are not on any list.  */	skb_unlink((struct sk_buff *) chunk);	list_del_init(&chunk->transmitted_list);	/* 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 = chunklen % 4;	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 = chunk->skb->tail;	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,			  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 = chunk->skb->tail;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){	__u16 ssn;	__u16 sid;	if (chunk->has_ssn)		return;	/* This is the last possible instant to assign a SSN. */	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {		ssn = 0;	} else {		sid = htons(chunk->subh.data_hdr->stream);		if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)			ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid);		else			ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid);		ssn = htons(ssn);	}	chunk->subh.data_hdr->ssn = ssn;	chunk->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, int 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(skb->nh.iph->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. */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;	headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;	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;	retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC);	if (!retval) {		*cookie_len = 0;		goto nodata;	}	/* Clear this memory since we are sending this data structure	 * out on the network.	 */	memset(retval, 0x00, *cookie_len);	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;	/* 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) {		/* Sign the message.  */		sg.page = virt_to_page(&cookie->c);

⌨️ 快捷键说明

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