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

📄 ulpevent.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_length: sizeof (__u32)	 * This field is the total length of the notification data, including	 * the notification header.	 */	ssf->ssf_length = sizeof(struct sctp_send_failed) + len;	skb_trim(skb, ssf->ssf_length);	/* Socket Extensions for SCTP	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_error: 16 bits (unsigned integer)	 * This value represents the reason why the send failed, and if set,	 * will be a SCTP protocol error code as defined in [SCTP] section	 * 3.3.10.	 */	ssf->ssf_error = error;	/* Socket Extensions for SCTP	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_info: sizeof (struct sctp_sndrcvinfo)	 * The original send information associated with the undelivered	 * message.	 */	memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));	/* Per TSVWG discussion with Randy. Allow the application to	 * ressemble a fragmented message.	 */	ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;	/* Socket Extensions for SCTP	 * 5.3.1.4 SCTP_SEND_FAILED	 *	 * ssf_assoc_id: sizeof (sctp_assoc_t)	 * The association id field, sf_assoc_id, 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);	ssf->ssf_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* Create and initialize a SCTP_SHUTDOWN_EVENT notification. * * Socket Extensions for SCTP - draft-01 * 5.3.1.5 SCTP_SHUTDOWN_EVENT */struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(	const struct sctp_association *asoc,	__u16 flags, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_shutdown_event *sse;	struct sk_buff *skb;	event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event),				  MSG_NOTIFICATION, gfp);	if (!event)		goto fail;	skb = sctp_event2skb(event);	sse = (struct sctp_shutdown_event *)		skb_put(skb, sizeof(struct sctp_shutdown_event));	/* Socket Extensions for SCTP	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT	 *	 * sse_type	 * It should be SCTP_SHUTDOWN_EVENT	 */	sse->sse_type = SCTP_SHUTDOWN_EVENT;	/* Socket Extensions for SCTP	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT	 *	 * sse_flags: 16 bits (unsigned integer)	 * Currently unused.	 */	sse->sse_flags = 0;	/* Socket Extensions for SCTP	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT	 *	 * sse_length: sizeof (__u32)	 * This field is the total length of the notification data, including	 * the notification header.	 */	sse->sse_length = sizeof(struct sctp_shutdown_event);	/* Socket Extensions for SCTP	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT	 *	 * sse_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);	sse->sse_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* Create and initialize a SCTP_ADAPTATION_INDICATION notification. * * Socket Extensions for SCTP * 5.3.1.6 SCTP_ADAPTATION_INDICATION */struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(	const struct sctp_association *asoc, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_adaptation_event *sai;	struct sk_buff *skb;	event = sctp_ulpevent_new(sizeof(struct sctp_adaptation_event),				  MSG_NOTIFICATION, gfp);	if (!event)		goto fail;	skb = sctp_event2skb(event);	sai = (struct sctp_adaptation_event *)		skb_put(skb, sizeof(struct sctp_adaptation_event));	sai->sai_type = SCTP_ADAPTATION_INDICATION;	sai->sai_flags = 0;	sai->sai_length = sizeof(struct sctp_adaptation_event);	sai->sai_adaptation_ind = asoc->peer.adaptation_ind;	sctp_ulpevent_set_owner(event, asoc);	sai->sai_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* A message has been received.  Package this message as a notification * to pass it to the upper layers.  Go ahead and calculate the sndrcvinfo * even if filtered out later. * * Socket Extensions for SCTP * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) */struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,						struct sctp_chunk *chunk,						gfp_t gfp){	struct sctp_ulpevent *event = NULL;	struct sk_buff *skb;	size_t padding, len;	int rx_count;	/*	 * check to see if we need to make space for this	 * new skb, expand the rcvbuffer if needed, or drop	 * the frame	 */	if (asoc->ep->rcvbuf_policy)		rx_count = atomic_read(&asoc->rmem_alloc);	else		rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);	if (rx_count >= asoc->base.sk->sk_rcvbuf) {		if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) ||		    (!sk_rmem_schedule(asoc->base.sk, chunk->skb->truesize)))			goto fail;	}	/* Clone the original skb, sharing the data.  */	skb = skb_clone(chunk->skb, gfp);	if (!skb)		goto fail;	/* First calculate the padding, so we don't inadvertently	 * pass up the wrong length to the user.	 *	 * RFC 2960 - Section 3.2  Chunk Field Descriptions	 *	 * The total length of a chunk(including Type, Length and Value fields)	 * MUST be a multiple of 4 bytes.  If the length of the chunk is not a	 * multiple of 4 bytes, the sender MUST pad the chunk with all zero	 * bytes and this padding is not included in the chunk length field.	 * The sender should never pad with more than 3 bytes.  The receiver	 * MUST ignore the padding bytes.	 */	len = ntohs(chunk->chunk_hdr->length);	padding = WORD_ROUND(len) - len;	/* Fixup cloned skb with just this chunks data.  */	skb_trim(skb, chunk->chunk_end - padding - skb->data);	/* Embed the event fields inside the cloned skb.  */	event = sctp_skb2event(skb);	/* Initialize event with flags 0  and correct length	 * Since this is a clone of the original skb, only account for	 * the data of this chunk as other chunks will be accounted separately.	 */	sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff));	sctp_ulpevent_receive_data(event, asoc);	event->stream = ntohs(chunk->subh.data_hdr->stream);	event->ssn = ntohs(chunk->subh.data_hdr->ssn);	event->ppid = chunk->subh.data_hdr->ppid;	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {		event->flags |= SCTP_UNORDERED;		event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);	}	event->tsn = ntohl(chunk->subh.data_hdr->tsn);	event->msg_flags |= chunk->chunk_hdr->flags;	event->iif = sctp_chunk_iif(chunk);fail:	return event;}/* Create a partial delivery related event. * * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * *   When a receiver is engaged in a partial delivery of a *   message this notification will be used to indicate *   various events. */struct sctp_ulpevent *sctp_ulpevent_make_pdapi(	const struct sctp_association *asoc, __u32 indication,	gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_pdapi_event *pd;	struct sk_buff *skb;	event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event),				  MSG_NOTIFICATION, gfp);	if (!event)		goto fail;	skb = sctp_event2skb(event);	pd = (struct sctp_pdapi_event *)		skb_put(skb, sizeof(struct sctp_pdapi_event));	/* pdapi_type	 *   It should be SCTP_PARTIAL_DELIVERY_EVENT	 *	 * pdapi_flags: 16 bits (unsigned integer)	 *   Currently unused.	 */	pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;	pd->pdapi_flags = 0;	/* pdapi_length: 32 bits (unsigned integer)	 *	 * This field is the total length of the notification data, including	 * the notification header.  It will generally be sizeof (struct	 * sctp_pdapi_event).	 */	pd->pdapi_length = sizeof(struct sctp_pdapi_event);	/*  pdapi_indication: 32 bits (unsigned integer)	 *	 * This field holds the indication being sent to the application.	 */	pd->pdapi_indication = indication;	/*  pdapi_assoc_id: sizeof (sctp_assoc_t)	 *	 * The association id field, holds the identifier for the association.	 */	sctp_ulpevent_set_owner(event, asoc);	pd->pdapi_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}struct sctp_ulpevent *sctp_ulpevent_make_authkey(	const struct sctp_association *asoc, __u16 key_id,	__u32 indication, gfp_t gfp){	struct sctp_ulpevent *event;	struct sctp_authkey_event *ak;	struct sk_buff *skb;	event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event),				  MSG_NOTIFICATION, gfp);	if (!event)		goto fail;	skb = sctp_event2skb(event);	ak = (struct sctp_authkey_event *)		skb_put(skb, sizeof(struct sctp_authkey_event));	ak->auth_type = SCTP_AUTHENTICATION_INDICATION;	ak->auth_flags = 0;	ak->auth_length = sizeof(struct sctp_authkey_event);	ak->auth_keynumber = key_id;	ak->auth_altkeynumber = 0;	ak->auth_indication = indication;	/*	 * The association id field, holds the identifier for the association.	 */	sctp_ulpevent_set_owner(event, asoc);	ak->auth_assoc_id = sctp_assoc2id(asoc);	return event;fail:	return NULL;}/* Return the notification type, assuming this is a notification * event. */__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event){	union sctp_notification *notification;	struct sk_buff *skb;	skb = sctp_event2skb(event);	notification = (union sctp_notification *) skb->data;	return notification->sn_header.sn_type;}/* Copy out the sndrcvinfo into a msghdr.  */void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,				   struct msghdr *msghdr){	struct sctp_sndrcvinfo sinfo;	if (sctp_ulpevent_is_notification(event))		return;	/* Sockets API Extensions for SCTP	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)	 *	 * sinfo_stream: 16 bits (unsigned integer)	 *	 * For recvmsg() the SCTP stack places the message's stream number in	 * this value.	*/	sinfo.sinfo_stream = event->stream;	/* sinfo_ssn: 16 bits (unsigned integer)	 *	 * For recvmsg() this value contains the stream sequence number that	 * the remote endpoint placed in the DATA chunk.  For fragmented	 * messages this is the same number for all deliveries of the message	 * (if more than one recvmsg() is needed to read the message).	 */	sinfo.sinfo_ssn = event->ssn;	/* sinfo_ppid: 32 bits (unsigned integer)	 *	 * In recvmsg() this value is	 * the same information that was passed by the upper layer in the peer	 * application.  Please note that byte order issues are NOT accounted	 * for and this information is passed opaquely by the SCTP stack from	 * one end to the other.	 */	sinfo.sinfo_ppid = event->ppid;	/* sinfo_flags: 16 bits (unsigned integer)	 *	 * This field may contain any of the following flags and is composed of	 * a bitwise OR of these values.	 *	 * recvmsg() flags:	 *	 * SCTP_UNORDERED - This flag is present when the message was sent	 *                 non-ordered.	 */	sinfo.sinfo_flags = event->flags;	/* sinfo_tsn: 32 bit (unsigned integer)	 *	 * For the receiving side, this field holds a TSN that was	 * assigned to one of the SCTP Data Chunks.	 */	sinfo.sinfo_tsn = event->tsn;	/* sinfo_cumtsn: 32 bit (unsigned integer)	 *	 * This field will hold the current cumulative TSN as	 * known by the underlying SCTP layer.  Note this field is	 * ignored when sending and only valid for a receive	 * operation when sinfo_flags are set to SCTP_UNORDERED.	 */	sinfo.sinfo_cumtsn = event->cumtsn;	/* sinfo_assoc_id: sizeof (sctp_assoc_t)	 *	 * The association handle field, sinfo_assoc_id, holds the identifier	 * for the association announced in the COMMUNICATION_UP notification.	 * All notifications for a given association have the same identifier.	 * Ignored for one-to-one style sockets.	 */	sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);	/* context value that is set via SCTP_CONTEXT socket option. */	sinfo.sinfo_context = event->asoc->default_rcv_context;	/* These fields are not used while receiving. */	sinfo.sinfo_timetolive = 0;	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,		 sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);}/* Do accounting for bytes received and hold a reference to the association * for each skb. */static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,				       struct sctp_association *asoc){	struct sk_buff *skb, *frag;	skb = sctp_event2skb(event);	/* Set the owner and charge rwnd for bytes received.  */	sctp_ulpevent_set_owner(event, asoc);	sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));	if (!skb->data_len)		return;	/* Note:  Not clearing the entire event struct as this is just a	 * fragment of the real event.  However, we still need to do rwnd	 * accounting.	 * In general, the skb passed from IP can have only 1 level of	 * fragments. But we allow multiple levels of fragments.	 */	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {		sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc);	}}/* Do accounting for bytes just read by user and release the references to * the association. */static void sctp_ulpevent_release_data(struct sctp_ulpevent *event){	struct sk_buff *skb, *frag;	unsigned int	len;	/* Current stack structures assume that the rcv buffer is	 * per socket.   For UDP style sockets this is not true as	 * multiple associations may be on a single UDP-style socket.	 * Use the local private area of the skb to track the owning	 * association.	 */	skb = sctp_event2skb(event);	len = skb->len;	if (!skb->data_len)		goto done;	/* Don't forget the fragments. */	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {		/* NOTE:  skb_shinfos are recursive. Although IP returns		 * skb's with only 1 level of fragments, SCTP reassembly can		 * increase the levels.		 */		sctp_ulpevent_release_frag_data(sctp_skb2event(frag));	}done:	sctp_assoc_rwnd_increase(event->asoc, len);	sctp_ulpevent_release_owner(event);}static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event){	struct sk_buff *skb, *frag;	skb = sctp_event2skb(event);	if (!skb->data_len)		goto done;	/* Don't forget the fragments. */	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {		/* NOTE:  skb_shinfos are recursive. Although IP returns		 * skb's with only 1 level of fragments, SCTP reassembly can		 * increase the levels.		 */		sctp_ulpevent_release_frag_data(sctp_skb2event(frag));	}done:	sctp_ulpevent_release_owner(event);}/* Free a ulpevent that has an owner.  It includes releasing the reference * to the owner, updating the rwnd in case of a DATA event and freeing the * skb. */void sctp_ulpevent_free(struct sctp_ulpevent *event){	if (sctp_ulpevent_is_notification(event))		sctp_ulpevent_release_owner(event);	else		sctp_ulpevent_release_data(event);	kfree_skb(sctp_event2skb(event));}/* Purge the skb lists holding ulpevents. */void sctp_queue_purge_ulpevents(struct sk_buff_head *list){	struct sk_buff *skb;	while ((skb = skb_dequeue(list)) != NULL)		sctp_ulpevent_free(sctp_skb2event(skb));}

⌨️ 快捷键说明

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