cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inqueue.c (6509B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* SCTP kernel implementation
      3 * Copyright (c) 1999-2000 Cisco, Inc.
      4 * Copyright (c) 1999-2001 Motorola, Inc.
      5 * Copyright (c) 2002 International Business Machines, Corp.
      6 *
      7 * This file is part of the SCTP kernel implementation
      8 *
      9 * These functions are the methods for accessing the SCTP inqueue.
     10 *
     11 * An SCTP inqueue is a queue into which you push SCTP packets
     12 * (which might be bundles or fragments of chunks) and out of which you
     13 * pop SCTP whole chunks.
     14 *
     15 * Please send any bug reports or fixes you make to the
     16 * email address(es):
     17 *    lksctp developers <linux-sctp@vger.kernel.org>
     18 *
     19 * Written or modified by:
     20 *    La Monte H.P. Yarroll <piggy@acm.org>
     21 *    Karl Knutson <karl@athena.chicago.il.us>
     22 */
     23
     24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     25
     26#include <net/sctp/sctp.h>
     27#include <net/sctp/sm.h>
     28#include <linux/interrupt.h>
     29#include <linux/slab.h>
     30
     31/* Initialize an SCTP inqueue.  */
     32void sctp_inq_init(struct sctp_inq *queue)
     33{
     34	INIT_LIST_HEAD(&queue->in_chunk_list);
     35	queue->in_progress = NULL;
     36
     37	/* Create a task for delivering data.  */
     38	INIT_WORK(&queue->immediate, NULL);
     39}
     40
     41/* Release the memory associated with an SCTP inqueue.  */
     42void sctp_inq_free(struct sctp_inq *queue)
     43{
     44	struct sctp_chunk *chunk, *tmp;
     45
     46	/* Empty the queue.  */
     47	list_for_each_entry_safe(chunk, tmp, &queue->in_chunk_list, list) {
     48		list_del_init(&chunk->list);
     49		sctp_chunk_free(chunk);
     50	}
     51
     52	/* If there is a packet which is currently being worked on,
     53	 * free it as well.
     54	 */
     55	if (queue->in_progress) {
     56		sctp_chunk_free(queue->in_progress);
     57		queue->in_progress = NULL;
     58	}
     59}
     60
     61/* Put a new packet in an SCTP inqueue.
     62 * We assume that packet->sctp_hdr is set and in host byte order.
     63 */
     64void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
     65{
     66	/* Directly call the packet handling routine. */
     67	if (chunk->rcvr->dead) {
     68		sctp_chunk_free(chunk);
     69		return;
     70	}
     71
     72	/* We are now calling this either from the soft interrupt
     73	 * or from the backlog processing.
     74	 * Eventually, we should clean up inqueue to not rely
     75	 * on the BH related data structures.
     76	 */
     77	list_add_tail(&chunk->list, &q->in_chunk_list);
     78	if (chunk->asoc)
     79		chunk->asoc->stats.ipackets++;
     80	q->immediate.func(&q->immediate);
     81}
     82
     83/* Peek at the next chunk on the inqeue. */
     84struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue)
     85{
     86	struct sctp_chunk *chunk;
     87	struct sctp_chunkhdr *ch = NULL;
     88
     89	chunk = queue->in_progress;
     90	/* If there is no more chunks in this packet, say so */
     91	if (chunk->singleton ||
     92	    chunk->end_of_packet ||
     93	    chunk->pdiscard)
     94		    return NULL;
     95
     96	ch = (struct sctp_chunkhdr *)chunk->chunk_end;
     97
     98	return ch;
     99}
    100
    101
    102/* Extract a chunk from an SCTP inqueue.
    103 *
    104 * WARNING:  If you need to put the chunk on another queue, you need to
    105 * make a shallow copy (clone) of it.
    106 */
    107struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
    108{
    109	struct sctp_chunk *chunk;
    110	struct sctp_chunkhdr *ch = NULL;
    111
    112	/* The assumption is that we are safe to process the chunks
    113	 * at this time.
    114	 */
    115
    116	chunk = queue->in_progress;
    117	if (chunk) {
    118		/* There is a packet that we have been working on.
    119		 * Any post processing work to do before we move on?
    120		 */
    121		if (chunk->singleton ||
    122		    chunk->end_of_packet ||
    123		    chunk->pdiscard) {
    124			if (chunk->head_skb == chunk->skb) {
    125				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
    126				goto new_skb;
    127			}
    128			if (chunk->skb->next) {
    129				chunk->skb = chunk->skb->next;
    130				goto new_skb;
    131			}
    132
    133			if (chunk->head_skb)
    134				chunk->skb = chunk->head_skb;
    135			sctp_chunk_free(chunk);
    136			chunk = queue->in_progress = NULL;
    137		} else {
    138			/* Nothing to do. Next chunk in the packet, please. */
    139			ch = (struct sctp_chunkhdr *)chunk->chunk_end;
    140			/* Force chunk->skb->data to chunk->chunk_end.  */
    141			skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data);
    142			/* We are guaranteed to pull a SCTP header. */
    143		}
    144	}
    145
    146	/* Do we need to take the next packet out of the queue to process? */
    147	if (!chunk) {
    148		struct list_head *entry;
    149
    150next_chunk:
    151		/* Is the queue empty?  */
    152		entry = sctp_list_dequeue(&queue->in_chunk_list);
    153		if (!entry)
    154			return NULL;
    155
    156		chunk = list_entry(entry, struct sctp_chunk, list);
    157
    158		if (skb_is_gso(chunk->skb) && skb_is_gso_sctp(chunk->skb)) {
    159			/* GSO-marked skbs but without frags, handle
    160			 * them normally
    161			 */
    162			if (skb_shinfo(chunk->skb)->frag_list)
    163				chunk->head_skb = chunk->skb;
    164
    165			/* skbs with "cover letter" */
    166			if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len)
    167				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
    168
    169			if (WARN_ON(!chunk->skb)) {
    170				__SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
    171				sctp_chunk_free(chunk);
    172				goto next_chunk;
    173			}
    174		}
    175
    176		if (chunk->asoc)
    177			sock_rps_save_rxhash(chunk->asoc->base.sk, chunk->skb);
    178
    179		queue->in_progress = chunk;
    180
    181new_skb:
    182		/* This is the first chunk in the packet.  */
    183		ch = (struct sctp_chunkhdr *)chunk->skb->data;
    184		chunk->singleton = 1;
    185		chunk->data_accepted = 0;
    186		chunk->pdiscard = 0;
    187		chunk->auth = 0;
    188		chunk->has_asconf = 0;
    189		chunk->end_of_packet = 0;
    190		if (chunk->head_skb) {
    191			struct sctp_input_cb
    192				*cb = SCTP_INPUT_CB(chunk->skb),
    193				*head_cb = SCTP_INPUT_CB(chunk->head_skb);
    194
    195			cb->chunk = head_cb->chunk;
    196			cb->af = head_cb->af;
    197		}
    198	}
    199
    200	chunk->chunk_hdr = ch;
    201	chunk->chunk_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
    202	skb_pull(chunk->skb, sizeof(*ch));
    203	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
    204
    205	if (chunk->chunk_end + sizeof(*ch) <= skb_tail_pointer(chunk->skb)) {
    206		/* This is not a singleton */
    207		chunk->singleton = 0;
    208	} else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) {
    209		/* Discard inside state machine. */
    210		chunk->pdiscard = 1;
    211		chunk->chunk_end = skb_tail_pointer(chunk->skb);
    212	} else {
    213		/* We are at the end of the packet, so mark the chunk
    214		 * in case we need to send a SACK.
    215		 */
    216		chunk->end_of_packet = 1;
    217	}
    218
    219	pr_debug("+++sctp_inq_pop+++ chunk:%p[%s], length:%d, skb->len:%d\n",
    220		 chunk, sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)),
    221		 ntohs(chunk->chunk_hdr->length), chunk->skb->len);
    222
    223	return chunk;
    224}
    225
    226/* Set a top-half handler.
    227 *
    228 * Originally, we the top-half handler was scheduled as a BH.  We now
    229 * call the handler directly in sctp_inq_push() at a time that
    230 * we know we are lock safe.
    231 * The intent is that this routine will pull stuff out of the
    232 * inqueue and process it.
    233 */
    234void sctp_inq_set_th_handler(struct sctp_inq *q, work_func_t callback)
    235{
    236	INIT_WORK(&q->immediate, callback);
    237}