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

📄 ulpevent.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * * These functions manipulate an sctp event.   The struct ulpevent is used * to carry notifications and data to the ULP (sockets). * * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This SCTP implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied *                 ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING.  If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): *    lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: *    http://www.sf.net/projects/lksctp * * Written or modified by: *    Jon Grimm             <jgrimm@us.ibm.com> *    La Monte H.P. Yarroll <piggy@acm.org> *    Ardelle Fan	    <ardelle.fan@intel.com> *    Sridhar Samudrala     <sri@us.ibm.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */#include <linux/types.h>#include <linux/skbuff.h>#include <net/sctp/structs.h>#include <net/sctp/sctp.h>#include <net/sctp/sm.h>static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,				       struct sctp_association *asoc);static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);/* Initialize an ULP event from an given skb.  */SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event,				    int msg_flags,				    unsigned int len){	memset(event, 0, sizeof(struct sctp_ulpevent));	event->msg_flags = msg_flags;	event->rmem_len = len;}/* Create a new sctp_ulpevent.  */SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,						    gfp_t gfp){	struct sctp_ulpevent *event;	struct sk_buff *skb;	skb = alloc_skb(size, gfp);	if (!skb)		goto fail;	event = sctp_skb2event(skb);	sctp_ulpevent_init(event, msg_flags, skb->truesize);	return event;fail:	return NULL;}/* Is this a MSG_NOTIFICATION?  */int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event){	return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);}/* Hold the association in case the msg_name needs read out of * the association. */static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,					   const struct sctp_association *asoc){	struct sk_buff *skb;	/* Cast away the const, as we are just wanting to	 * bump the reference count.	 */	sctp_association_hold((struct sctp_association *)asoc);	skb = sctp_event2skb(event);	event->asoc = (struct sctp_association *)asoc;	atomic_add(event->rmem_len, &event->asoc->rmem_alloc);	sctp_skb_set_owner_r(skb, asoc->base.sk);}/* A simple destructor to give up the reference to the association. */static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event){	struct sctp_association *asoc = event->asoc;	atomic_sub(event->rmem_len, &asoc->rmem_alloc);	sctp_association_put(asoc);}/* Create and initialize an SCTP_ASSOC_CHANGE event. * * 5.3.1.1 SCTP_ASSOC_CHANGE * * Communication notifications inform the ULP that an SCTP association * has either begun or ended. The identifier for a new association is * provided by this notification. * * Note: There is no field checking here.  If a field is unused it will be * zero'd out. */struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(	const struct sctp_association *asoc,	__u16 flags, __u16 state, __u16 error, __u16 outbound,	__u16 inbound, struct sctp_chunk *chunk, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_assoc_change *sac;	struct sk_buff *skb;	/* If the lower layer passed in the chunk, it will be	 * an ABORT, so we need to include it in the sac_info.	 */	if (chunk) {		/* Copy the chunk data to a new skb and reserve enough		 * head room to use as notification.		 */		skb = skb_copy_expand(chunk->skb,				      sizeof(struct sctp_assoc_change), 0, gfp);		if (!skb)			goto fail;		/* Embed the event fields inside the cloned skb.  */		event = sctp_skb2event(skb);		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);		/* Include the notification structure */		sac = (struct sctp_assoc_change *)			skb_push(skb, sizeof(struct sctp_assoc_change));		/* Trim the buffer to the right length.  */		skb_trim(skb, sizeof(struct sctp_assoc_change) +			 ntohs(chunk->chunk_hdr->length) -			 sizeof(sctp_chunkhdr_t));	} else {		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),				  MSG_NOTIFICATION, gfp);		if (!event)			goto fail;		skb = sctp_event2skb(event);		sac = (struct sctp_assoc_change *) skb_put(skb,					sizeof(struct sctp_assoc_change));	}	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_type:	 * It should be SCTP_ASSOC_CHANGE.	 */	sac->sac_type = SCTP_ASSOC_CHANGE;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_state: 32 bits (signed integer)	 * This field holds one of a number of values that communicate the	 * event that happened to the association.	 */	sac->sac_state = state;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_flags: 16 bits (unsigned integer)	 * Currently unused.	 */	sac->sac_flags = 0;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_length: sizeof (__u32)	 * This field is the total length of the notification data, including	 * the notification header.	 */	sac->sac_length = skb->len;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_error:  32 bits (signed integer)	 *	 * If the state was reached due to a error condition (e.g.	 * COMMUNICATION_LOST) any relevant error information is available in	 * this field. This corresponds to the protocol error codes defined in	 * [SCTP].	 */	sac->sac_error = error;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_outbound_streams:  16 bits (unsigned integer)	 * sac_inbound_streams:  16 bits (unsigned integer)	 *	 * The maximum number of streams allowed in each direction are	 * available in sac_outbound_streams and sac_inbound streams.	 */	sac->sac_outbound_streams = outbound;	sac->sac_inbound_streams = inbound;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * sac_assoc_id: sizeof (sctp_assoc_t)	 *	 * The association id field, holds the identifier for the association.	 * All notifications for a given association have the same association	 * identifier.  For TCP style socket, this field is ignored.	 */	sctp_ulpevent_set_owner(event, asoc);	sac->sac_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* Create and initialize an SCTP_PEER_ADDR_CHANGE event. * * Socket Extensions for SCTP - draft-01 * 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * When a destination address on a multi-homed peer encounters a change * an interface details event is sent. */struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(	const struct sctp_association *asoc,	const struct sockaddr_storage *aaddr,	int flags, int state, int error, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_paddr_change  *spc;	struct sk_buff *skb;	event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),				  MSG_NOTIFICATION, gfp);	if (!event)		goto fail;	skb = sctp_event2skb(event);	spc = (struct sctp_paddr_change *)		skb_put(skb, sizeof(struct sctp_paddr_change));	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_type:	 *	 *    It should be SCTP_PEER_ADDR_CHANGE.	 */	spc->spc_type = SCTP_PEER_ADDR_CHANGE;	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_length: sizeof (__u32)	 *	 * This field is the total length of the notification data, including	 * the notification header.	 */	spc->spc_length = sizeof(struct sctp_paddr_change);	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_flags: 16 bits (unsigned integer)	 * Currently unused.	 */	spc->spc_flags = 0;	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_state:  32 bits (signed integer)	 *	 * This field holds one of a number of values that communicate the	 * event that happened to the address.	 */	spc->spc_state = state;	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_error:  32 bits (signed integer)	 *	 * If the state was reached due to any error condition (e.g.	 * ADDRESS_UNREACHABLE) any relevant error information is available in	 * this field.	 */	spc->spc_error = error;	/* Socket Extensions for SCTP	 * 5.3.1.1 SCTP_ASSOC_CHANGE	 *	 * spc_assoc_id: sizeof (sctp_assoc_t)	 *	 * The association id field, holds the identifier for the association.	 * All notifications for a given association have the same association	 * identifier.  For TCP style socket, this field is ignored.	 */	sctp_ulpevent_set_owner(event, asoc);	spc->spc_assoc_id = sctp_assoc2id(asoc);	/* Sockets API Extensions for SCTP	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE	 *	 * spc_aaddr: sizeof (struct sockaddr_storage)	 *	 * The affected address field, holds the remote peer's address that is	 * encountering the change of state.	 */	memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));	/* Map ipv4 address into v4-mapped-on-v6 address.  */	sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map(					sctp_sk(asoc->base.sk),					(union sctp_addr *)&spc->spc_aaddr);	return event;fail:	return NULL;}/* Create and initialize an SCTP_REMOTE_ERROR notification. * * Note: This assumes that the chunk->skb->data already points to the * operation error payload. * * Socket Extensions for SCTP - draft-01 * 5.3.1.3 SCTP_REMOTE_ERROR * * A remote peer may send an Operational Error message to its peer. * This message indicates a variety of error conditions on an * association. The entire error TLV as it appears on the wire is * included in a SCTP_REMOTE_ERROR event.  Please refer to the SCTP * specification [SCTP] and any extensions for a list of possible * error formats. */struct sctp_ulpevent *sctp_ulpevent_make_remote_error(	const struct sctp_association *asoc, struct sctp_chunk *chunk,	__u16 flags, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_remote_error *sre;	struct sk_buff *skb;	sctp_errhdr_t *ch;	__be16 cause;	int elen;	ch = (sctp_errhdr_t *)(chunk->skb->data);	cause = ch->cause;	elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);	/* Pull off the ERROR header.  */	skb_pull(chunk->skb, sizeof(sctp_errhdr_t));	/* Copy the skb to a new skb with room for us to prepend	 * notification with.	 */	skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),			      0, gfp);	/* Pull off the rest of the cause TLV from the chunk.  */	skb_pull(chunk->skb, elen);	if (!skb)		goto fail;	/* Embed the event fields inside the cloned skb.  */	event = sctp_skb2event(skb);	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);	sre = (struct sctp_remote_error *)		skb_push(skb, sizeof(struct sctp_remote_error));	/* Trim the buffer to the right length.  */	skb_trim(skb, sizeof(struct sctp_remote_error) + elen);	/* Socket Extensions for SCTP	 * 5.3.1.3 SCTP_REMOTE_ERROR	 *	 * sre_type:	 *   It should be SCTP_REMOTE_ERROR.	 */	sre->sre_type = SCTP_REMOTE_ERROR;	/*	 * Socket Extensions for SCTP	 * 5.3.1.3 SCTP_REMOTE_ERROR	 *	 * sre_flags: 16 bits (unsigned integer)	 *   Currently unused.	 */	sre->sre_flags = 0;	/* Socket Extensions for SCTP	 * 5.3.1.3 SCTP_REMOTE_ERROR	 *	 * sre_length: sizeof (__u32)	 *	 * This field is the total length of the notification data,	 * including the notification header.	 */	sre->sre_length = skb->len;	/* Socket Extensions for SCTP	 * 5.3.1.3 SCTP_REMOTE_ERROR	 *	 * sre_error: 16 bits (unsigned integer)	 * This value represents one of the Operational Error causes defined in	 * the SCTP specification, in network byte order.	 */	sre->sre_error = cause;	/* Socket Extensions for SCTP	 * 5.3.1.3 SCTP_REMOTE_ERROR	 *	 * sre_assoc_id: sizeof (sctp_assoc_t)	 *	 * The association id field, holds the identifier for the association.	 * All notifications for a given association have the same association	 * identifier.  For TCP style socket, this field is ignored.	 */	sctp_ulpevent_set_owner(event, asoc);	sre->sre_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* Create and initialize a SCTP_SEND_FAILED notification. * * Socket Extensions for SCTP - draft-01 * 5.3.1.4 SCTP_SEND_FAILED */struct sctp_ulpevent *sctp_ulpevent_make_send_failed(	const struct sctp_association *asoc, struct sctp_chunk *chunk,	__u16 flags, __u32 error, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_send_failed *ssf;	struct sk_buff *skb;	/* Pull off any padding. */	int len = ntohs(chunk->chunk_hdr->length);	/* Make skb with more room so we can prepend notification.  */	skb = skb_copy_expand(chunk->skb,			      sizeof(struct sctp_send_failed), /* headroom */			      0,                               /* tailroom */			      gfp);	if (!skb)		goto fail;	/* Pull off the common chunk header and DATA header.  */	skb_pull(skb, sizeof(struct sctp_data_chunk));	len -= sizeof(struct sctp_data_chunk);	/* Embed the event fields inside the cloned skb.  */	event = sctp_skb2event(skb);	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);	ssf = (struct sctp_send_failed *)		skb_push(skb, sizeof(struct sctp_send_failed));	/* Socket Extensions for SCTP	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_type:	 * It should be SCTP_SEND_FAILED.	 */	ssf->ssf_type = SCTP_SEND_FAILED;	/* Socket Extensions for SCTP	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_flags: 16 bits (unsigned integer)	 * The flag value will take one of the following values	 *	 * SCTP_DATA_UNSENT - Indicates that the data was never put on	 *                    the wire.	 *	 * SCTP_DATA_SENT   - Indicates that the data was put on the wire.	 *                    Note that this does not necessarily mean that the	 *                    data was (or was not) successfully delivered.	 */	ssf->ssf_flags = flags;	/* Socket Extensions for SCTP

⌨️ 快捷键说明

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