net/sctp/ulpqueue.c

Source file repositories/reference/linux-study-clean/net/sctp/ulpqueue.c

File Facts

System
Linux kernel
Corpus path
net/sctp/ulpqueue.c
Extension
.c
Size
29245 bytes
Lines
1127
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!skb_queue_empty(&sp->pd_lobby)) {
			skb_queue_splice_tail_init(&sp->pd_lobby,
						   &sk->sk_receive_queue);
			return 1;
		}
	} else {
		/* There are other associations in PD, so we only need to
		 * pull stuff out of the lobby that belongs to the
		 * associations that is exiting PD (all of its notifications
		 * are posted here).
		 */
		if (!skb_queue_empty(&sp->pd_lobby) && asoc) {
			struct sk_buff *skb, *tmp;
			struct sctp_ulpevent *event;

			sctp_skb_for_each(skb, &sp->pd_lobby, tmp) {
				event = sctp_skb2event(skb);
				if (event->asoc == asoc) {
					__skb_unlink(skb, &sp->pd_lobby);
					__skb_queue_tail(&sk->sk_receive_queue,
							 skb);
				}
			}
		}
	}

	return 0;
}

/* Set the pd_mode on the socket and ulpq */
static void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq)
{
	struct sctp_sock *sp = sctp_sk(ulpq->asoc->base.sk);

	atomic_inc(&sp->pd_mode);
	ulpq->pd_mode = 1;
}

/* Clear the pd_mode and restart any pending messages waiting for delivery. */
static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
{
	ulpq->pd_mode = 0;
	sctp_ulpq_reasm_drain(ulpq);
	return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc);
}

int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sk_buff_head *skb_list)
{
	struct sock *sk = ulpq->asoc->base.sk;
	struct sctp_sock *sp = sctp_sk(sk);
	struct sctp_ulpevent *event;
	struct sk_buff_head *queue;
	struct sk_buff *skb;
	int clear_pd = 0;

	skb = __skb_peek(skb_list);
	event = sctp_skb2event(skb);

	/* If the socket is just going to throw this away, do not
	 * even try to deliver it.
	 */
	if (sk->sk_shutdown & RCV_SHUTDOWN &&
	    (sk->sk_shutdown & SEND_SHUTDOWN ||
	     !sctp_ulpevent_is_notification(event)))
		goto out_free;

	if (!sctp_ulpevent_is_notification(event)) {
		sk_mark_napi_id(sk, skb);
		sk_incoming_cpu_update(sk);
	}
	/* Check if the user wishes to receive this event.  */
	if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe))
		goto out_free;

	/* If we are in partial delivery mode, post to the lobby until
	 * partial delivery is cleared, unless, of course _this_ is
	 * the association the cause of the partial delivery.
	 */

	if (atomic_read(&sp->pd_mode) == 0) {
		queue = &sk->sk_receive_queue;
	} else {
		if (ulpq->pd_mode) {
			/* If the association is in partial delivery, we
			 * need to finish delivering the partially processed
			 * packet before passing any other data.  This is
			 * because we don't truly support stream interleaving.
			 */
			if ((event->msg_flags & MSG_NOTIFICATION) ||
			    (SCTP_DATA_NOT_FRAG ==

Annotation

Implementation Notes