Blame view

net/sctp/inqueue.c 6.36 KB
47505b8bc   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
2
  /* SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
   * Copyright (c) 1999-2000 Cisco, Inc.
   * Copyright (c) 1999-2001 Motorola, Inc.
   * Copyright (c) 2002 International Business Machines, Corp.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
6
   *
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
7
   * This file is part of the SCTP kernel implementation
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   * These functions are the methods for accessing the SCTP inqueue.
   *
   * An SCTP inqueue is a queue into which you push SCTP packets
   * (which might be bundles or fragments of chunks) and out of which you
   * pop SCTP whole chunks.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
14
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
   * Please send any bug reports or fixes you make to the
   * email address(es):
91705c61b   Daniel Borkmann   net: sctp: trivia...
17
   *    lksctp developers <linux-sctp@vger.kernel.org>
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
18
   *
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
19
   * Written or modified by:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
   *    La Monte H.P. Yarroll <piggy@acm.org>
   *    Karl Knutson <karl@athena.chicago.il.us>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
145ce502e   Joe Perches   net/sctp: Use pr_...
23
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  #include <net/sctp/sctp.h>
  #include <net/sctp/sm.h>
  #include <linux/interrupt.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  
  /* Initialize an SCTP inqueue.  */
  void sctp_inq_init(struct sctp_inq *queue)
  {
79af02c25   David S. Miller   [SCTP]: Use struc...
32
  	INIT_LIST_HEAD(&queue->in_chunk_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  	queue->in_progress = NULL;
  
  	/* Create a task for delivering data.  */
c4028958b   David Howells   WorkStruct: make ...
36
  	INIT_WORK(&queue->immediate, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
  }
  
  /* Release the memory associated with an SCTP inqueue.  */
  void sctp_inq_free(struct sctp_inq *queue)
  {
79af02c25   David S. Miller   [SCTP]: Use struc...
42
  	struct sctp_chunk *chunk, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  
  	/* Empty the queue.  */
79af02c25   David S. Miller   [SCTP]: Use struc...
45
46
  	list_for_each_entry_safe(chunk, tmp, &queue->in_chunk_list, list) {
  		list_del_init(&chunk->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  		sctp_chunk_free(chunk);
79af02c25   David S. Miller   [SCTP]: Use struc...
48
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
  
  	/* If there is a packet which is currently being worked on,
  	 * free it as well.
  	 */
7a48f923b   Sridhar Samudrala   [SCTP]: Fix poten...
53
  	if (queue->in_progress) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  		sctp_chunk_free(queue->in_progress);
7a48f923b   Sridhar Samudrala   [SCTP]: Fix poten...
55
56
  		queue->in_progress = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
  }
  
  /* Put a new packet in an SCTP inqueue.
   * We assume that packet->sctp_hdr is set and in host byte order.
   */
ac0b04627   Sridhar Samudrala   [SCTP]: Extend /p...
62
  void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  {
  	/* Directly call the packet handling routine. */
027f6e1ad   Vlad Yasevich   SCTP: Fix a poten...
65
66
67
68
  	if (chunk->rcvr->dead) {
  		sctp_chunk_free(chunk);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
  
  	/* We are now calling this either from the soft interrupt
  	 * or from the backlog processing.
  	 * Eventually, we should clean up inqueue to not rely
  	 * on the BH related data structures.
  	 */
ac0b04627   Sridhar Samudrala   [SCTP]: Extend /p...
75
  	list_add_tail(&chunk->list, &q->in_chunk_list);
196d67593   Michele Baldessari   sctp: Add support...
76
77
  	if (chunk->asoc)
  		chunk->asoc->stats.ipackets++;
c4028958b   David Howells   WorkStruct: make ...
78
  	q->immediate.func(&q->immediate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  }
bbd0d5980   Vlad Yasevich   [SCTP]: Implement...
80
81
82
83
  /* Peek at the next chunk on the inqeue. */
  struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue)
  {
  	struct sctp_chunk *chunk;
922dbc5be   Xin Long   sctp: remove the ...
84
  	struct sctp_chunkhdr *ch = NULL;
bbd0d5980   Vlad Yasevich   [SCTP]: Implement...
85
86
87
88
89
90
91
  
  	chunk = queue->in_progress;
  	/* If there is no more chunks in this packet, say so */
  	if (chunk->singleton ||
  	    chunk->end_of_packet ||
  	    chunk->pdiscard)
  		    return NULL;
922dbc5be   Xin Long   sctp: remove the ...
92
  	ch = (struct sctp_chunkhdr *)chunk->chunk_end;
bbd0d5980   Vlad Yasevich   [SCTP]: Implement...
93
94
95
  
  	return ch;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
  /* Extract a chunk from an SCTP inqueue.
   *
   * WARNING:  If you need to put the chunk on another queue, you need to
   * make a shallow copy (clone) of it.
   */
  struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
  {
  	struct sctp_chunk *chunk;
922dbc5be   Xin Long   sctp: remove the ...
104
  	struct sctp_chunkhdr *ch = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
  
  	/* The assumption is that we are safe to process the chunks
  	 * at this time.
  	 */
3acb50c18   Marcelo Ricardo Leitner   sctp: delay as mu...
109
110
  	chunk = queue->in_progress;
  	if (chunk) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
  		/* There is a packet that we have been working on.
  		 * Any post processing work to do before we move on?
  		 */
  		if (chunk->singleton ||
  		    chunk->end_of_packet ||
  		    chunk->pdiscard) {
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
117
118
119
120
121
122
123
124
125
126
127
  			if (chunk->head_skb == chunk->skb) {
  				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
  				goto new_skb;
  			}
  			if (chunk->skb->next) {
  				chunk->skb = chunk->skb->next;
  				goto new_skb;
  			}
  
  			if (chunk->head_skb)
  				chunk->skb = chunk->head_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
  			sctp_chunk_free(chunk);
  			chunk = queue->in_progress = NULL;
  		} else {
  			/* Nothing to do. Next chunk in the packet, please. */
922dbc5be   Xin Long   sctp: remove the ...
132
  			ch = (struct sctp_chunkhdr *)chunk->chunk_end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  			/* Force chunk->skb->data to chunk->chunk_end.  */
26b87c788   Daniel Borkmann   net: sctp: fix re...
134
135
  			skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data);
  			/* We are guaranteed to pull a SCTP header. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
  		}
  	}
  
  	/* Do we need to take the next packet out of the queue to process? */
  	if (!chunk) {
79af02c25   David S. Miller   [SCTP]: Use struc...
141
  		struct list_head *entry;
3acb50c18   Marcelo Ricardo Leitner   sctp: delay as mu...
142
  next_chunk:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  		/* Is the queue empty?  */
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
144
145
  		entry = sctp_list_dequeue(&queue->in_chunk_list);
  		if (!entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  			return NULL;
3acb50c18   Marcelo Ricardo Leitner   sctp: delay as mu...
147
  		chunk = list_entry(entry, struct sctp_chunk, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

1dd27cde3   Daniel Axtens   net: use skb_is_g...
149
  		if (skb_is_gso(chunk->skb) && skb_is_gso_sctp(chunk->skb)) {
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  			/* GSO-marked skbs but without frags, handle
  			 * them normally
  			 */
  			if (skb_shinfo(chunk->skb)->frag_list)
  				chunk->head_skb = chunk->skb;
  
  			/* skbs with "cover letter" */
  			if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len)
  				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
  
  			if (WARN_ON(!chunk->skb)) {
  				__SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
  				sctp_chunk_free(chunk);
  				goto next_chunk;
  			}
  		}
  
  		if (chunk->asoc)
  			sock_rps_save_rxhash(chunk->asoc->base.sk, chunk->skb);
3acb50c18   Marcelo Ricardo Leitner   sctp: delay as mu...
169
  		queue->in_progress = chunk;
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
170
  new_skb:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		/* This is the first chunk in the packet.  */
922dbc5be   Xin Long   sctp: remove the ...
172
  		ch = (struct sctp_chunkhdr *)chunk->skb->data;
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
173
  		chunk->singleton = 1;
7c3ceb4fb   Neil Horman   [SCTP]: Allow spi...
174
  		chunk->data_accepted = 0;
90017accf   Marcelo Ricardo Leitner   sctp: Add GSO sup...
175
176
177
178
  		chunk->pdiscard = 0;
  		chunk->auth = 0;
  		chunk->has_asconf = 0;
  		chunk->end_of_packet = 0;
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
179
180
181
182
183
184
  		if (chunk->head_skb) {
  			struct sctp_input_cb
  				*cb = SCTP_INPUT_CB(chunk->skb),
  				*head_cb = SCTP_INPUT_CB(chunk->head_skb);
  
  			cb->chunk = head_cb->chunk;
e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
185
  			cb->af = head_cb->af;
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
186
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	}
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
188
  	chunk->chunk_hdr = ch;
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
189
  	chunk->chunk_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
922dbc5be   Xin Long   sctp: remove the ...
190
  	skb_pull(chunk->skb, sizeof(*ch));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
ce402f044   Xin Long   sctp: fix the iss...
192
  	if (chunk->chunk_end + sizeof(*ch) <= skb_tail_pointer(chunk->skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  		/* This is not a singleton */
  		chunk->singleton = 0;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
195
  	} else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) {
26b87c788   Daniel Borkmann   net: sctp: fix re...
196
197
198
  		/* Discard inside state machine. */
  		chunk->pdiscard = 1;
  		chunk->chunk_end = skb_tail_pointer(chunk->skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
  	} else {
  		/* We are at the end of the packet, so mark the chunk
  		 * in case we need to send a SACK.
  		 */
  		chunk->end_of_packet = 1;
  	}
bb33381d0   Daniel Borkmann   net: sctp: rework...
205
206
207
208
  	pr_debug("+++sctp_inq_pop+++ chunk:%p[%s], length:%d, skb->len:%d
  ",
  		 chunk, sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)),
  		 ntohs(chunk->chunk_hdr->length), chunk->skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
  	return chunk;
  }
  
  /* Set a top-half handler.
   *
   * Originally, we the top-half handler was scheduled as a BH.  We now
   * call the handler directly in sctp_inq_push() at a time that
   * we know we are lock safe.
   * The intent is that this routine will pull stuff out of the
   * inqueue and process it.
   */
c4028958b   David Howells   WorkStruct: make ...
220
  void sctp_inq_set_th_handler(struct sctp_inq *q, work_func_t callback)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  {
c4028958b   David Howells   WorkStruct: make ...
222
  	INIT_WORK(&q->immediate, callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  }