|
1 /*- |
|
2 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. |
|
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
|
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * a) Redistributions of source code must retain the above copyright notice, |
|
10 * this list of conditions and the following disclaimer. |
|
11 * |
|
12 * b) Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in |
|
14 * the documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its |
|
17 * contributors may be used to endorse or promote products derived |
|
18 * from this software without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
30 * THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 #ifdef __FreeBSD__ |
|
34 #include <sys/cdefs.h> |
|
35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 262252 2014-02-20 20:14:43Z tuexen $"); |
|
36 #endif |
|
37 |
|
38 #include <netinet/sctp_os.h> |
|
39 #include <netinet/sctp_var.h> |
|
40 #include <netinet/sctp_sysctl.h> |
|
41 #include <netinet/sctp_pcb.h> |
|
42 #include <netinet/sctp_header.h> |
|
43 #include <netinet/sctputil.h> |
|
44 #include <netinet/sctp_output.h> |
|
45 #include <netinet/sctp_input.h> |
|
46 #include <netinet/sctp_auth.h> |
|
47 #include <netinet/sctp_indata.h> |
|
48 #include <netinet/sctp_asconf.h> |
|
49 #include <netinet/sctp_bsd_addr.h> |
|
50 #include <netinet/sctp_timer.h> |
|
51 #include <netinet/sctp_crc32.h> |
|
52 #if !defined(__Userspace_os_Windows) |
|
53 #include <netinet/udp.h> |
|
54 #endif |
|
55 #if defined(__FreeBSD__) |
|
56 #include <sys/smp.h> |
|
57 #endif |
|
58 |
|
59 #if defined(__APPLE__) |
|
60 #define APPLE_FILE_NO 2 |
|
61 #endif |
|
62 |
|
63 |
|
64 static void |
|
65 sctp_stop_all_cookie_timers(struct sctp_tcb *stcb) |
|
66 { |
|
67 struct sctp_nets *net; |
|
68 |
|
69 /* This now not only stops all cookie timers |
|
70 * it also stops any INIT timers as well. This |
|
71 * will make sure that the timers are stopped in |
|
72 * all collision cases. |
|
73 */ |
|
74 SCTP_TCB_LOCK_ASSERT(stcb); |
|
75 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
76 if (net->rxt_timer.type == SCTP_TIMER_TYPE_COOKIE) { |
|
77 sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, |
|
78 stcb->sctp_ep, |
|
79 stcb, |
|
80 net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_1); |
|
81 } else if (net->rxt_timer.type == SCTP_TIMER_TYPE_INIT) { |
|
82 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, |
|
83 stcb->sctp_ep, |
|
84 stcb, |
|
85 net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_2); |
|
86 } |
|
87 } |
|
88 } |
|
89 |
|
90 /* INIT handler */ |
|
91 static void |
|
92 sctp_handle_init(struct mbuf *m, int iphlen, int offset, |
|
93 struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, |
|
94 struct sctp_init_chunk *cp, struct sctp_inpcb *inp, |
|
95 struct sctp_tcb *stcb, int *abort_no_unlock, |
|
96 #if defined(__FreeBSD__) |
|
97 uint8_t use_mflowid, uint32_t mflowid, |
|
98 #endif |
|
99 uint32_t vrf_id, uint16_t port) |
|
100 { |
|
101 struct sctp_init *init; |
|
102 struct mbuf *op_err; |
|
103 |
|
104 SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_init: handling INIT tcb:%p\n", |
|
105 (void *)stcb); |
|
106 if (stcb == NULL) { |
|
107 SCTP_INP_RLOCK(inp); |
|
108 } |
|
109 /* validate length */ |
|
110 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_chunk)) { |
|
111 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
112 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, |
|
113 #if defined(__FreeBSD__) |
|
114 use_mflowid, mflowid, |
|
115 #endif |
|
116 vrf_id, port); |
|
117 if (stcb) |
|
118 *abort_no_unlock = 1; |
|
119 goto outnow; |
|
120 } |
|
121 /* validate parameters */ |
|
122 init = &cp->init; |
|
123 if (init->initiate_tag == 0) { |
|
124 /* protocol error... send abort */ |
|
125 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
126 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, |
|
127 #if defined(__FreeBSD__) |
|
128 use_mflowid, mflowid, |
|
129 #endif |
|
130 vrf_id, port); |
|
131 if (stcb) |
|
132 *abort_no_unlock = 1; |
|
133 goto outnow; |
|
134 } |
|
135 if (ntohl(init->a_rwnd) < SCTP_MIN_RWND) { |
|
136 /* invalid parameter... send abort */ |
|
137 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
138 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, |
|
139 #if defined(__FreeBSD__) |
|
140 use_mflowid, mflowid, |
|
141 #endif |
|
142 vrf_id, port); |
|
143 if (stcb) |
|
144 *abort_no_unlock = 1; |
|
145 goto outnow; |
|
146 } |
|
147 if (init->num_inbound_streams == 0) { |
|
148 /* protocol error... send abort */ |
|
149 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
150 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, |
|
151 #if defined(__FreeBSD__) |
|
152 use_mflowid, mflowid, |
|
153 #endif |
|
154 vrf_id, port); |
|
155 if (stcb) |
|
156 *abort_no_unlock = 1; |
|
157 goto outnow; |
|
158 } |
|
159 if (init->num_outbound_streams == 0) { |
|
160 /* protocol error... send abort */ |
|
161 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
162 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, |
|
163 #if defined(__FreeBSD__) |
|
164 use_mflowid, mflowid, |
|
165 #endif |
|
166 vrf_id, port); |
|
167 if (stcb) |
|
168 *abort_no_unlock = 1; |
|
169 goto outnow; |
|
170 } |
|
171 if (sctp_validate_init_auth_params(m, offset + sizeof(*cp), |
|
172 offset + ntohs(cp->ch.chunk_length))) { |
|
173 /* auth parameter(s) error... send abort */ |
|
174 sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, NULL, |
|
175 #if defined(__FreeBSD__) |
|
176 use_mflowid, mflowid, |
|
177 #endif |
|
178 vrf_id, port); |
|
179 if (stcb) |
|
180 *abort_no_unlock = 1; |
|
181 goto outnow; |
|
182 } |
|
183 /* We are only accepting if we have a socket with positive so_qlimit.*/ |
|
184 if ((stcb == NULL) && |
|
185 ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || |
|
186 (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || |
|
187 (inp->sctp_socket == NULL) || |
|
188 (inp->sctp_socket->so_qlimit == 0))) { |
|
189 /* |
|
190 * FIX ME ?? What about TCP model and we have a |
|
191 * match/restart case? Actually no fix is needed. |
|
192 * the lookup will always find the existing assoc so stcb |
|
193 * would not be NULL. It may be questionable to do this |
|
194 * since we COULD just send back the INIT-ACK and hope that |
|
195 * the app did accept()'s by the time the COOKIE was sent. But |
|
196 * there is a price to pay for COOKIE generation and I don't |
|
197 * want to pay it on the chance that the app will actually do |
|
198 * some accepts(). The App just looses and should NOT be in |
|
199 * this state :-) |
|
200 */ |
|
201 if (SCTP_BASE_SYSCTL(sctp_blackhole) == 0) { |
|
202 sctp_send_abort(m, iphlen, src, dst, sh, 0, NULL, |
|
203 #if defined(__FreeBSD__) |
|
204 use_mflowid, mflowid, |
|
205 #endif |
|
206 vrf_id, port); |
|
207 } |
|
208 goto outnow; |
|
209 } |
|
210 if ((stcb != NULL) && |
|
211 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
|
212 SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending SHUTDOWN-ACK\n"); |
|
213 sctp_send_shutdown_ack(stcb, NULL); |
|
214 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); |
|
215 } else { |
|
216 SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n"); |
|
217 sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, src, dst, |
|
218 sh, cp, |
|
219 #if defined(__FreeBSD__) |
|
220 use_mflowid, mflowid, |
|
221 #endif |
|
222 vrf_id, port, |
|
223 ((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED)); |
|
224 } |
|
225 outnow: |
|
226 if (stcb == NULL) { |
|
227 SCTP_INP_RUNLOCK(inp); |
|
228 } |
|
229 } |
|
230 |
|
231 /* |
|
232 * process peer "INIT/INIT-ACK" chunk returns value < 0 on error |
|
233 */ |
|
234 |
|
235 int |
|
236 sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked |
|
237 #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) |
|
238 SCTP_UNUSED |
|
239 #endif |
|
240 ) |
|
241 { |
|
242 int unsent_data = 0; |
|
243 unsigned int i; |
|
244 struct sctp_stream_queue_pending *sp; |
|
245 struct sctp_association *asoc; |
|
246 |
|
247 /* This function returns the number of streams that have |
|
248 * true unsent data on them. Note that as it looks through |
|
249 * it will clean up any places that have old data that |
|
250 * has been sent but left at top of stream queue. |
|
251 */ |
|
252 asoc = &stcb->asoc; |
|
253 SCTP_TCB_SEND_LOCK(stcb); |
|
254 if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { |
|
255 /* Check to see if some data queued */ |
|
256 for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
|
257 /*sa_ignore FREED_MEMORY*/ |
|
258 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue); |
|
259 if (sp == NULL) { |
|
260 continue; |
|
261 } |
|
262 if ((sp->msg_is_complete) && |
|
263 (sp->length == 0) && |
|
264 (sp->sender_all_done)) { |
|
265 /* We are doing differed cleanup. Last |
|
266 * time through when we took all the data |
|
267 * the sender_all_done was not set. |
|
268 */ |
|
269 if (sp->put_last_out == 0) { |
|
270 SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); |
|
271 SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", |
|
272 sp->sender_all_done, |
|
273 sp->length, |
|
274 sp->msg_is_complete, |
|
275 sp->put_last_out); |
|
276 } |
|
277 atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); |
|
278 TAILQ_REMOVE(&stcb->asoc.strmout[i].outqueue, sp, next); |
|
279 if (sp->net) { |
|
280 sctp_free_remote_addr(sp->net); |
|
281 sp->net = NULL; |
|
282 } |
|
283 if (sp->data) { |
|
284 sctp_m_freem(sp->data); |
|
285 sp->data = NULL; |
|
286 } |
|
287 sctp_free_a_strmoq(stcb, sp, so_locked); |
|
288 } else { |
|
289 unsent_data++; |
|
290 break; |
|
291 } |
|
292 } |
|
293 } |
|
294 SCTP_TCB_SEND_UNLOCK(stcb); |
|
295 return (unsent_data); |
|
296 } |
|
297 |
|
298 static int |
|
299 sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) |
|
300 { |
|
301 struct sctp_init *init; |
|
302 struct sctp_association *asoc; |
|
303 struct sctp_nets *lnet; |
|
304 unsigned int i; |
|
305 |
|
306 init = &cp->init; |
|
307 asoc = &stcb->asoc; |
|
308 /* save off parameters */ |
|
309 asoc->peer_vtag = ntohl(init->initiate_tag); |
|
310 asoc->peers_rwnd = ntohl(init->a_rwnd); |
|
311 /* init tsn's */ |
|
312 asoc->highest_tsn_inside_map = asoc->asconf_seq_in = ntohl(init->initial_tsn) - 1; |
|
313 |
|
314 if (!TAILQ_EMPTY(&asoc->nets)) { |
|
315 /* update any ssthresh's that may have a default */ |
|
316 TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { |
|
317 lnet->ssthresh = asoc->peers_rwnd; |
|
318 if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE|SCTP_CWND_LOGGING_ENABLE)) { |
|
319 sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_INITIALIZATION); |
|
320 } |
|
321 |
|
322 } |
|
323 } |
|
324 SCTP_TCB_SEND_LOCK(stcb); |
|
325 if (asoc->pre_open_streams > ntohs(init->num_inbound_streams)) { |
|
326 unsigned int newcnt; |
|
327 struct sctp_stream_out *outs; |
|
328 struct sctp_stream_queue_pending *sp, *nsp; |
|
329 struct sctp_tmit_chunk *chk, *nchk; |
|
330 |
|
331 /* abandon the upper streams */ |
|
332 newcnt = ntohs(init->num_inbound_streams); |
|
333 TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { |
|
334 if (chk->rec.data.stream_number >= newcnt) { |
|
335 TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); |
|
336 asoc->send_queue_cnt--; |
|
337 if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { |
|
338 asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; |
|
339 #ifdef INVARIANTS |
|
340 } else { |
|
341 panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number); |
|
342 #endif |
|
343 } |
|
344 if (chk->data != NULL) { |
|
345 sctp_free_bufspace(stcb, asoc, chk, 1); |
|
346 sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, |
|
347 0, chk, SCTP_SO_NOT_LOCKED); |
|
348 if (chk->data) { |
|
349 sctp_m_freem(chk->data); |
|
350 chk->data = NULL; |
|
351 } |
|
352 } |
|
353 sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
|
354 /*sa_ignore FREED_MEMORY*/ |
|
355 } |
|
356 } |
|
357 if (asoc->strmout) { |
|
358 for (i = newcnt; i < asoc->pre_open_streams; i++) { |
|
359 outs = &asoc->strmout[i]; |
|
360 TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { |
|
361 TAILQ_REMOVE(&outs->outqueue, sp, next); |
|
362 asoc->stream_queue_cnt--; |
|
363 sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, |
|
364 stcb, 0, sp, SCTP_SO_NOT_LOCKED); |
|
365 if (sp->data) { |
|
366 sctp_m_freem(sp->data); |
|
367 sp->data = NULL; |
|
368 } |
|
369 if (sp->net) { |
|
370 sctp_free_remote_addr(sp->net); |
|
371 sp->net = NULL; |
|
372 } |
|
373 /* Free the chunk */ |
|
374 sctp_free_a_strmoq(stcb, sp, SCTP_SO_NOT_LOCKED); |
|
375 /*sa_ignore FREED_MEMORY*/ |
|
376 } |
|
377 } |
|
378 } |
|
379 /* cut back the count */ |
|
380 asoc->pre_open_streams = newcnt; |
|
381 } |
|
382 SCTP_TCB_SEND_UNLOCK(stcb); |
|
383 asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams; |
|
384 |
|
385 /* EY - nr_sack: initialize highest tsn in nr_mapping_array */ |
|
386 asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map; |
|
387 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { |
|
388 sctp_log_map(0, 5, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); |
|
389 } |
|
390 /* This is the next one we expect */ |
|
391 asoc->str_reset_seq_in = asoc->asconf_seq_in + 1; |
|
392 |
|
393 asoc->mapping_array_base_tsn = ntohl(init->initial_tsn); |
|
394 asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->asconf_seq_in; |
|
395 |
|
396 asoc->advanced_peer_ack_point = asoc->last_acked_seq; |
|
397 /* open the requested streams */ |
|
398 |
|
399 if (asoc->strmin != NULL) { |
|
400 /* Free the old ones */ |
|
401 struct sctp_queued_to_read *ctl, *nctl; |
|
402 |
|
403 for (i = 0; i < asoc->streamincnt; i++) { |
|
404 TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) { |
|
405 TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next); |
|
406 sctp_free_remote_addr(ctl->whoFrom); |
|
407 ctl->whoFrom = NULL; |
|
408 sctp_m_freem(ctl->data); |
|
409 ctl->data = NULL; |
|
410 sctp_free_a_readq(stcb, ctl); |
|
411 } |
|
412 } |
|
413 SCTP_FREE(asoc->strmin, SCTP_M_STRMI); |
|
414 } |
|
415 if (asoc->max_inbound_streams > ntohs(init->num_outbound_streams)) { |
|
416 asoc->streamincnt = ntohs(init->num_outbound_streams); |
|
417 } else { |
|
418 asoc->streamincnt = asoc->max_inbound_streams; |
|
419 } |
|
420 SCTP_MALLOC(asoc->strmin, struct sctp_stream_in *, asoc->streamincnt * |
|
421 sizeof(struct sctp_stream_in), SCTP_M_STRMI); |
|
422 if (asoc->strmin == NULL) { |
|
423 /* we didn't get memory for the streams! */ |
|
424 SCTPDBG(SCTP_DEBUG_INPUT2, "process_init: couldn't get memory for the streams!\n"); |
|
425 return (-1); |
|
426 } |
|
427 for (i = 0; i < asoc->streamincnt; i++) { |
|
428 asoc->strmin[i].stream_no = i; |
|
429 asoc->strmin[i].last_sequence_delivered = 0xffff; |
|
430 TAILQ_INIT(&asoc->strmin[i].inqueue); |
|
431 asoc->strmin[i].delivery_started = 0; |
|
432 } |
|
433 /* |
|
434 * load_address_from_init will put the addresses into the |
|
435 * association when the COOKIE is processed or the INIT-ACK is |
|
436 * processed. Both types of COOKIE's existing and new call this |
|
437 * routine. It will remove addresses that are no longer in the |
|
438 * association (for the restarting case where addresses are |
|
439 * removed). Up front when the INIT arrives we will discard it if it |
|
440 * is a restart and new addresses have been added. |
|
441 */ |
|
442 /* sa_ignore MEMLEAK */ |
|
443 return (0); |
|
444 } |
|
445 |
|
446 /* |
|
447 * INIT-ACK message processing/consumption returns value < 0 on error |
|
448 */ |
|
449 static int |
|
450 sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, |
|
451 struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, |
|
452 struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb, |
|
453 struct sctp_nets *net, int *abort_no_unlock, |
|
454 #if defined(__FreeBSD__) |
|
455 uint8_t use_mflowid, uint32_t mflowid, |
|
456 #endif |
|
457 uint32_t vrf_id) |
|
458 { |
|
459 struct sctp_association *asoc; |
|
460 struct mbuf *op_err; |
|
461 int retval, abort_flag; |
|
462 uint32_t initack_limit; |
|
463 int nat_friendly = 0; |
|
464 |
|
465 /* First verify that we have no illegal param's */ |
|
466 abort_flag = 0; |
|
467 |
|
468 op_err = sctp_arethere_unrecognized_parameters(m, |
|
469 (offset + sizeof(struct sctp_init_chunk)), |
|
470 &abort_flag, (struct sctp_chunkhdr *)cp, &nat_friendly); |
|
471 if (abort_flag) { |
|
472 /* Send an abort and notify peer */ |
|
473 sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); |
|
474 *abort_no_unlock = 1; |
|
475 return (-1); |
|
476 } |
|
477 asoc = &stcb->asoc; |
|
478 asoc->peer_supports_nat = (uint8_t)nat_friendly; |
|
479 /* process the peer's parameters in the INIT-ACK */ |
|
480 retval = sctp_process_init((struct sctp_init_chunk *)cp, stcb); |
|
481 if (retval < 0) { |
|
482 return (retval); |
|
483 } |
|
484 initack_limit = offset + ntohs(cp->ch.chunk_length); |
|
485 /* load all addresses */ |
|
486 if ((retval = sctp_load_addresses_from_init(stcb, m, |
|
487 (offset + sizeof(struct sctp_init_chunk)), initack_limit, |
|
488 src, dst, NULL))) { |
|
489 /* Huh, we should abort */ |
|
490 SCTPDBG(SCTP_DEBUG_INPUT1, |
|
491 "Load addresses from INIT causes an abort %d\n", |
|
492 retval); |
|
493 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
494 src, dst, sh, NULL, |
|
495 #if defined(__FreeBSD__) |
|
496 use_mflowid, mflowid, |
|
497 #endif |
|
498 vrf_id, net->port); |
|
499 *abort_no_unlock = 1; |
|
500 return (-1); |
|
501 } |
|
502 /* if the peer doesn't support asconf, flush the asconf queue */ |
|
503 if (asoc->peer_supports_asconf == 0) { |
|
504 struct sctp_asconf_addr *param, *nparam; |
|
505 |
|
506 TAILQ_FOREACH_SAFE(param, &asoc->asconf_queue, next, nparam) { |
|
507 TAILQ_REMOVE(&asoc->asconf_queue, param, next); |
|
508 SCTP_FREE(param, SCTP_M_ASC_ADDR); |
|
509 } |
|
510 } |
|
511 |
|
512 stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs, |
|
513 stcb->asoc.local_hmacs); |
|
514 if (op_err) { |
|
515 sctp_queue_op_err(stcb, op_err); |
|
516 /* queuing will steal away the mbuf chain to the out queue */ |
|
517 op_err = NULL; |
|
518 } |
|
519 /* extract the cookie and queue it to "echo" it back... */ |
|
520 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
521 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
522 stcb->asoc.overall_error_count, |
|
523 0, |
|
524 SCTP_FROM_SCTP_INPUT, |
|
525 __LINE__); |
|
526 } |
|
527 stcb->asoc.overall_error_count = 0; |
|
528 net->error_count = 0; |
|
529 |
|
530 /* |
|
531 * Cancel the INIT timer, We do this first before queueing the |
|
532 * cookie. We always cancel at the primary to assue that we are |
|
533 * canceling the timer started by the INIT which always goes to the |
|
534 * primary. |
|
535 */ |
|
536 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb, |
|
537 asoc->primary_destination, SCTP_FROM_SCTP_INPUT+SCTP_LOC_4); |
|
538 |
|
539 /* calculate the RTO */ |
|
540 net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, sctp_align_safe_nocopy, |
|
541 SCTP_RTT_FROM_NON_DATA); |
|
542 |
|
543 retval = sctp_send_cookie_echo(m, offset, stcb, net); |
|
544 if (retval < 0) { |
|
545 /* |
|
546 * No cookie, we probably should send a op error. But in any |
|
547 * case if there is no cookie in the INIT-ACK, we can |
|
548 * abandon the peer, its broke. |
|
549 */ |
|
550 if (retval == -3) { |
|
551 /* We abort with an error of missing mandatory param */ |
|
552 op_err = |
|
553 sctp_generate_invmanparam(SCTP_CAUSE_MISSING_PARAM); |
|
554 if (op_err) { |
|
555 /* |
|
556 * Expand beyond to include the mandatory |
|
557 * param cookie |
|
558 */ |
|
559 struct sctp_inv_mandatory_param *mp; |
|
560 |
|
561 SCTP_BUF_LEN(op_err) = |
|
562 sizeof(struct sctp_inv_mandatory_param); |
|
563 mp = mtod(op_err, |
|
564 struct sctp_inv_mandatory_param *); |
|
565 /* Subtract the reserved param */ |
|
566 mp->length = |
|
567 htons(sizeof(struct sctp_inv_mandatory_param) - 2); |
|
568 mp->num_param = htonl(1); |
|
569 mp->param = htons(SCTP_STATE_COOKIE); |
|
570 mp->resv = 0; |
|
571 } |
|
572 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
573 src, dst, sh, op_err, |
|
574 #if defined(__FreeBSD__) |
|
575 use_mflowid, mflowid, |
|
576 #endif |
|
577 vrf_id, net->port); |
|
578 *abort_no_unlock = 1; |
|
579 } |
|
580 return (retval); |
|
581 } |
|
582 |
|
583 return (0); |
|
584 } |
|
585 |
|
586 static void |
|
587 sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, |
|
588 struct sctp_tcb *stcb, struct sctp_nets *net) |
|
589 { |
|
590 struct sockaddr_storage store; |
|
591 struct sctp_nets *r_net, *f_net; |
|
592 struct timeval tv; |
|
593 int req_prim = 0; |
|
594 uint16_t old_error_counter; |
|
595 #ifdef INET |
|
596 struct sockaddr_in *sin; |
|
597 #endif |
|
598 #ifdef INET6 |
|
599 struct sockaddr_in6 *sin6; |
|
600 #endif |
|
601 #if defined(__Userspace__) |
|
602 struct sockaddr_conn *sconn; |
|
603 #endif |
|
604 |
|
605 if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_heartbeat_chunk)) { |
|
606 /* Invalid length */ |
|
607 return; |
|
608 } |
|
609 |
|
610 memset(&store, 0, sizeof(store)); |
|
611 switch (cp->heartbeat.hb_info.addr_family) { |
|
612 #ifdef INET |
|
613 case AF_INET: |
|
614 if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in)) { |
|
615 sin = (struct sockaddr_in *)&store; |
|
616 sin->sin_family = cp->heartbeat.hb_info.addr_family; |
|
617 #ifdef HAVE_SIN_LEN |
|
618 sin->sin_len = cp->heartbeat.hb_info.addr_len; |
|
619 #endif |
|
620 sin->sin_port = stcb->rport; |
|
621 memcpy(&sin->sin_addr, cp->heartbeat.hb_info.address, |
|
622 sizeof(sin->sin_addr)); |
|
623 } else { |
|
624 return; |
|
625 } |
|
626 break; |
|
627 #endif |
|
628 #ifdef INET6 |
|
629 case AF_INET6: |
|
630 if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_in6)) { |
|
631 sin6 = (struct sockaddr_in6 *)&store; |
|
632 sin6->sin6_family = cp->heartbeat.hb_info.addr_family; |
|
633 #ifdef HAVE_SIN6_LEN |
|
634 sin6->sin6_len = cp->heartbeat.hb_info.addr_len; |
|
635 #endif |
|
636 sin6->sin6_port = stcb->rport; |
|
637 memcpy(&sin6->sin6_addr, cp->heartbeat.hb_info.address, |
|
638 sizeof(sin6->sin6_addr)); |
|
639 } else { |
|
640 return; |
|
641 } |
|
642 break; |
|
643 #endif |
|
644 #if defined(__Userspace__) |
|
645 case AF_CONN: |
|
646 if (cp->heartbeat.hb_info.addr_len == sizeof(struct sockaddr_conn)) { |
|
647 sconn = (struct sockaddr_conn *)&store; |
|
648 sconn->sconn_family = cp->heartbeat.hb_info.addr_family; |
|
649 #ifdef HAVE_SCONN_LEN |
|
650 sconn->sconn_len = cp->heartbeat.hb_info.addr_len; |
|
651 #endif |
|
652 sconn->sconn_port = stcb->rport; |
|
653 memcpy(&sconn->sconn_addr, cp->heartbeat.hb_info.address, |
|
654 sizeof(sconn->sconn_addr)); |
|
655 } else { |
|
656 return; |
|
657 } |
|
658 break; |
|
659 #endif |
|
660 default: |
|
661 return; |
|
662 } |
|
663 r_net = sctp_findnet(stcb, (struct sockaddr *)&store); |
|
664 if (r_net == NULL) { |
|
665 SCTPDBG(SCTP_DEBUG_INPUT1, "Huh? I can't find the address I sent it to, discard\n"); |
|
666 return; |
|
667 } |
|
668 if ((r_net && (r_net->dest_state & SCTP_ADDR_UNCONFIRMED)) && |
|
669 (r_net->heartbeat_random1 == cp->heartbeat.hb_info.random_value1) && |
|
670 (r_net->heartbeat_random2 == cp->heartbeat.hb_info.random_value2)) { |
|
671 /* |
|
672 * If the its a HB and it's random value is correct when can |
|
673 * confirm the destination. |
|
674 */ |
|
675 r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; |
|
676 if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) { |
|
677 stcb->asoc.primary_destination = r_net; |
|
678 r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; |
|
679 f_net = TAILQ_FIRST(&stcb->asoc.nets); |
|
680 if (f_net != r_net) { |
|
681 /* first one on the list is NOT the primary |
|
682 * sctp_cmpaddr() is much more efficent if |
|
683 * the primary is the first on the list, make it |
|
684 * so. |
|
685 */ |
|
686 TAILQ_REMOVE(&stcb->asoc.nets, r_net, sctp_next); |
|
687 TAILQ_INSERT_HEAD(&stcb->asoc.nets, r_net, sctp_next); |
|
688 } |
|
689 req_prim = 1; |
|
690 } |
|
691 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, |
|
692 stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); |
|
693 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); |
|
694 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); |
|
695 } |
|
696 old_error_counter = r_net->error_count; |
|
697 r_net->error_count = 0; |
|
698 r_net->hb_responded = 1; |
|
699 tv.tv_sec = cp->heartbeat.hb_info.time_value_1; |
|
700 tv.tv_usec = cp->heartbeat.hb_info.time_value_2; |
|
701 /* Now lets do a RTO with this */ |
|
702 r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy, |
|
703 SCTP_RTT_FROM_NON_DATA); |
|
704 if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) { |
|
705 r_net->dest_state |= SCTP_ADDR_REACHABLE; |
|
706 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, |
|
707 0, (void *)r_net, SCTP_SO_NOT_LOCKED); |
|
708 } |
|
709 if (r_net->dest_state & SCTP_ADDR_PF) { |
|
710 r_net->dest_state &= ~SCTP_ADDR_PF; |
|
711 stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net); |
|
712 } |
|
713 if (old_error_counter > 0) { |
|
714 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); |
|
715 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); |
|
716 } |
|
717 if (r_net == stcb->asoc.primary_destination) { |
|
718 if (stcb->asoc.alternate) { |
|
719 /* release the alternate, primary is good */ |
|
720 sctp_free_remote_addr(stcb->asoc.alternate); |
|
721 stcb->asoc.alternate = NULL; |
|
722 } |
|
723 } |
|
724 /* Mobility adaptation */ |
|
725 if (req_prim) { |
|
726 if ((sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
727 SCTP_MOBILITY_BASE) || |
|
728 sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
729 SCTP_MOBILITY_FASTHANDOFF)) && |
|
730 sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
731 SCTP_MOBILITY_PRIM_DELETED)) { |
|
732 |
|
733 sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7); |
|
734 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
735 SCTP_MOBILITY_FASTHANDOFF)) { |
|
736 sctp_assoc_immediate_retrans(stcb, |
|
737 stcb->asoc.primary_destination); |
|
738 } |
|
739 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
740 SCTP_MOBILITY_BASE)) { |
|
741 sctp_move_chunks_from_net(stcb, |
|
742 stcb->asoc.deleted_primary); |
|
743 } |
|
744 sctp_delete_prim_timer(stcb->sctp_ep, stcb, |
|
745 stcb->asoc.deleted_primary); |
|
746 } |
|
747 } |
|
748 } |
|
749 |
|
750 static int |
|
751 sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) |
|
752 { |
|
753 /* return 0 means we want you to proceed with the abort |
|
754 * non-zero means no abort processing |
|
755 */ |
|
756 struct sctpasochead *head; |
|
757 |
|
758 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { |
|
759 /* generate a new vtag and send init */ |
|
760 LIST_REMOVE(stcb, sctp_asocs); |
|
761 stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1); |
|
762 head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; |
|
763 /* put it in the bucket in the vtag hash of assoc's for the system */ |
|
764 LIST_INSERT_HEAD(head, stcb, sctp_asocs); |
|
765 sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); |
|
766 return (1); |
|
767 } |
|
768 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { |
|
769 /* treat like a case where the cookie expired i.e.: |
|
770 * - dump current cookie. |
|
771 * - generate a new vtag. |
|
772 * - resend init. |
|
773 */ |
|
774 /* generate a new vtag and send init */ |
|
775 LIST_REMOVE(stcb, sctp_asocs); |
|
776 stcb->asoc.state &= ~SCTP_STATE_COOKIE_ECHOED; |
|
777 stcb->asoc.state |= SCTP_STATE_COOKIE_WAIT; |
|
778 sctp_stop_all_cookie_timers(stcb); |
|
779 sctp_toss_old_cookies(stcb, &stcb->asoc); |
|
780 stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1); |
|
781 head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; |
|
782 /* put it in the bucket in the vtag hash of assoc's for the system */ |
|
783 LIST_INSERT_HEAD(head, stcb, sctp_asocs); |
|
784 sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); |
|
785 return (1); |
|
786 } |
|
787 return (0); |
|
788 } |
|
789 |
|
790 static int |
|
791 sctp_handle_nat_missing_state(struct sctp_tcb *stcb, |
|
792 struct sctp_nets *net) |
|
793 |
|
794 { |
|
795 /* return 0 means we want you to proceed with the abort |
|
796 * non-zero means no abort processing |
|
797 */ |
|
798 if (stcb->asoc.peer_supports_auth == 0) { |
|
799 SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_nat_missing_state: Peer does not support AUTH, cannot send an asconf\n"); |
|
800 return (0); |
|
801 } |
|
802 sctp_asconf_send_nat_state_update(stcb, net); |
|
803 return (1); |
|
804 } |
|
805 |
|
806 |
|
807 static void |
|
808 sctp_handle_abort(struct sctp_abort_chunk *abort, |
|
809 struct sctp_tcb *stcb, struct sctp_nets *net) |
|
810 { |
|
811 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
812 struct socket *so; |
|
813 #endif |
|
814 uint16_t len; |
|
815 uint16_t error; |
|
816 |
|
817 SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: handling ABORT\n"); |
|
818 if (stcb == NULL) |
|
819 return; |
|
820 |
|
821 len = ntohs(abort->ch.chunk_length); |
|
822 if (len > sizeof (struct sctp_chunkhdr)) { |
|
823 /* Need to check the cause codes for our |
|
824 * two magic nat aborts which don't kill the assoc |
|
825 * necessarily. |
|
826 */ |
|
827 struct sctp_missing_nat_state *natc; |
|
828 |
|
829 natc = (struct sctp_missing_nat_state *)(abort + 1); |
|
830 error = ntohs(natc->cause); |
|
831 if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) { |
|
832 SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n", |
|
833 abort->ch.chunk_flags); |
|
834 if (sctp_handle_nat_colliding_state(stcb)) { |
|
835 return; |
|
836 } |
|
837 } else if (error == SCTP_CAUSE_NAT_MISSING_STATE) { |
|
838 SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n", |
|
839 abort->ch.chunk_flags); |
|
840 if (sctp_handle_nat_missing_state(stcb, net)) { |
|
841 return; |
|
842 } |
|
843 } |
|
844 } else { |
|
845 error = 0; |
|
846 } |
|
847 /* stop any receive timers */ |
|
848 sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_6); |
|
849 /* notify user of the abort and clean up... */ |
|
850 sctp_abort_notification(stcb, 1, error, abort, SCTP_SO_NOT_LOCKED); |
|
851 /* free the tcb */ |
|
852 SCTP_STAT_INCR_COUNTER32(sctps_aborted); |
|
853 if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || |
|
854 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
855 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
856 } |
|
857 #ifdef SCTP_ASOCLOG_OF_TSNS |
|
858 sctp_print_out_track_log(stcb); |
|
859 #endif |
|
860 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
861 so = SCTP_INP_SO(stcb->sctp_ep); |
|
862 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
863 SCTP_TCB_UNLOCK(stcb); |
|
864 SCTP_SOCKET_LOCK(so, 1); |
|
865 SCTP_TCB_LOCK(stcb); |
|
866 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
867 #endif |
|
868 stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; |
|
869 (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, |
|
870 SCTP_FROM_SCTP_INPUT+SCTP_LOC_6); |
|
871 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
872 SCTP_SOCKET_UNLOCK(so, 1); |
|
873 #endif |
|
874 SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n"); |
|
875 } |
|
876 |
|
877 static void |
|
878 sctp_start_net_timers(struct sctp_tcb *stcb) |
|
879 { |
|
880 uint32_t cnt_hb_sent; |
|
881 struct sctp_nets *net; |
|
882 |
|
883 cnt_hb_sent = 0; |
|
884 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
885 /* For each network start: |
|
886 * 1) A pmtu timer. |
|
887 * 2) A HB timer |
|
888 * 3) If the dest in unconfirmed send |
|
889 * a hb as well if under max_hb_burst have |
|
890 * been sent. |
|
891 */ |
|
892 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); |
|
893 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); |
|
894 if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && |
|
895 (cnt_hb_sent < SCTP_BASE_SYSCTL(sctp_hb_maxburst))) { |
|
896 sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
|
897 cnt_hb_sent++; |
|
898 } |
|
899 } |
|
900 if (cnt_hb_sent) { |
|
901 sctp_chunk_output(stcb->sctp_ep, stcb, |
|
902 SCTP_OUTPUT_FROM_COOKIE_ACK, |
|
903 SCTP_SO_NOT_LOCKED); |
|
904 } |
|
905 } |
|
906 |
|
907 |
|
908 static void |
|
909 sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, |
|
910 struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag) |
|
911 { |
|
912 struct sctp_association *asoc; |
|
913 int some_on_streamwheel; |
|
914 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
915 struct socket *so; |
|
916 #endif |
|
917 |
|
918 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
919 "sctp_handle_shutdown: handling SHUTDOWN\n"); |
|
920 if (stcb == NULL) |
|
921 return; |
|
922 asoc = &stcb->asoc; |
|
923 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || |
|
924 (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { |
|
925 return; |
|
926 } |
|
927 if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_shutdown_chunk)) { |
|
928 /* Shutdown NOT the expected size */ |
|
929 return; |
|
930 } else { |
|
931 sctp_update_acked(stcb, cp, abort_flag); |
|
932 if (*abort_flag) { |
|
933 return; |
|
934 } |
|
935 } |
|
936 if (asoc->control_pdapi) { |
|
937 /* With a normal shutdown |
|
938 * we assume the end of last record. |
|
939 */ |
|
940 SCTP_INP_READ_LOCK(stcb->sctp_ep); |
|
941 asoc->control_pdapi->end_added = 1; |
|
942 asoc->control_pdapi->pdapi_aborted = 1; |
|
943 asoc->control_pdapi = NULL; |
|
944 SCTP_INP_READ_UNLOCK(stcb->sctp_ep); |
|
945 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
946 so = SCTP_INP_SO(stcb->sctp_ep); |
|
947 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
948 SCTP_TCB_UNLOCK(stcb); |
|
949 SCTP_SOCKET_LOCK(so, 1); |
|
950 SCTP_TCB_LOCK(stcb); |
|
951 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
952 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
953 /* assoc was freed while we were unlocked */ |
|
954 SCTP_SOCKET_UNLOCK(so, 1); |
|
955 return; |
|
956 } |
|
957 #endif |
|
958 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); |
|
959 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
960 SCTP_SOCKET_UNLOCK(so, 1); |
|
961 #endif |
|
962 } |
|
963 /* goto SHUTDOWN_RECEIVED state to block new requests */ |
|
964 if (stcb->sctp_socket) { |
|
965 if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
|
966 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) && |
|
967 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) { |
|
968 SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_RECEIVED); |
|
969 SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); |
|
970 /* notify upper layer that peer has initiated a shutdown */ |
|
971 sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
972 |
|
973 /* reset time */ |
|
974 (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); |
|
975 } |
|
976 } |
|
977 if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { |
|
978 /* |
|
979 * stop the shutdown timer, since we WILL move to |
|
980 * SHUTDOWN-ACK-SENT. |
|
981 */ |
|
982 sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_8); |
|
983 } |
|
984 /* Now is there unsent data on a stream somewhere? */ |
|
985 some_on_streamwheel = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED); |
|
986 |
|
987 if (!TAILQ_EMPTY(&asoc->send_queue) || |
|
988 !TAILQ_EMPTY(&asoc->sent_queue) || |
|
989 some_on_streamwheel) { |
|
990 /* By returning we will push more data out */ |
|
991 return; |
|
992 } else { |
|
993 /* no outstanding data to send, so move on... */ |
|
994 /* send SHUTDOWN-ACK */ |
|
995 /* move to SHUTDOWN-ACK-SENT state */ |
|
996 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || |
|
997 (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
998 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
999 } |
|
1000 SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); |
|
1001 SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); |
|
1002 sctp_stop_timers_for_shutdown(stcb); |
|
1003 sctp_send_shutdown_ack(stcb, net); |
|
1004 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, |
|
1005 stcb, net); |
|
1006 } |
|
1007 } |
|
1008 |
|
1009 static void |
|
1010 sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, |
|
1011 struct sctp_tcb *stcb, |
|
1012 struct sctp_nets *net) |
|
1013 { |
|
1014 struct sctp_association *asoc; |
|
1015 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1016 struct socket *so; |
|
1017 |
|
1018 so = SCTP_INP_SO(stcb->sctp_ep); |
|
1019 #endif |
|
1020 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1021 "sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n"); |
|
1022 if (stcb == NULL) |
|
1023 return; |
|
1024 |
|
1025 asoc = &stcb->asoc; |
|
1026 /* process according to association state */ |
|
1027 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || |
|
1028 (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { |
|
1029 /* unexpected SHUTDOWN-ACK... do OOTB handling... */ |
|
1030 sctp_send_shutdown_complete(stcb, net, 1); |
|
1031 SCTP_TCB_UNLOCK(stcb); |
|
1032 return; |
|
1033 } |
|
1034 if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && |
|
1035 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
|
1036 /* unexpected SHUTDOWN-ACK... so ignore... */ |
|
1037 SCTP_TCB_UNLOCK(stcb); |
|
1038 return; |
|
1039 } |
|
1040 if (asoc->control_pdapi) { |
|
1041 /* With a normal shutdown |
|
1042 * we assume the end of last record. |
|
1043 */ |
|
1044 SCTP_INP_READ_LOCK(stcb->sctp_ep); |
|
1045 asoc->control_pdapi->end_added = 1; |
|
1046 asoc->control_pdapi->pdapi_aborted = 1; |
|
1047 asoc->control_pdapi = NULL; |
|
1048 SCTP_INP_READ_UNLOCK(stcb->sctp_ep); |
|
1049 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1050 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1051 SCTP_TCB_UNLOCK(stcb); |
|
1052 SCTP_SOCKET_LOCK(so, 1); |
|
1053 SCTP_TCB_LOCK(stcb); |
|
1054 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
1055 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
1056 /* assoc was freed while we were unlocked */ |
|
1057 SCTP_SOCKET_UNLOCK(so, 1); |
|
1058 return; |
|
1059 } |
|
1060 #endif |
|
1061 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); |
|
1062 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1063 SCTP_SOCKET_UNLOCK(so, 1); |
|
1064 #endif |
|
1065 } |
|
1066 #ifdef INVARIANTS |
|
1067 if (!TAILQ_EMPTY(&asoc->send_queue) || |
|
1068 !TAILQ_EMPTY(&asoc->sent_queue) || |
|
1069 !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { |
|
1070 panic("Queues are not empty when handling SHUTDOWN-ACK"); |
|
1071 } |
|
1072 #endif |
|
1073 /* stop the timer */ |
|
1074 sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_9); |
|
1075 /* send SHUTDOWN-COMPLETE */ |
|
1076 sctp_send_shutdown_complete(stcb, net, 0); |
|
1077 /* notify upper layer protocol */ |
|
1078 if (stcb->sctp_socket) { |
|
1079 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
1080 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
1081 stcb->sctp_socket->so_snd.sb_cc = 0; |
|
1082 } |
|
1083 sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
1084 } |
|
1085 SCTP_STAT_INCR_COUNTER32(sctps_shutdown); |
|
1086 /* free the TCB but first save off the ep */ |
|
1087 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1088 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1089 SCTP_TCB_UNLOCK(stcb); |
|
1090 SCTP_SOCKET_LOCK(so, 1); |
|
1091 SCTP_TCB_LOCK(stcb); |
|
1092 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
1093 #endif |
|
1094 (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, |
|
1095 SCTP_FROM_SCTP_INPUT+SCTP_LOC_10); |
|
1096 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1097 SCTP_SOCKET_UNLOCK(so, 1); |
|
1098 #endif |
|
1099 } |
|
1100 |
|
1101 /* |
|
1102 * Skip past the param header and then we will find the chunk that caused the |
|
1103 * problem. There are two possiblities ASCONF or FWD-TSN other than that and |
|
1104 * our peer must be broken. |
|
1105 */ |
|
1106 static void |
|
1107 sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr, |
|
1108 struct sctp_nets *net) |
|
1109 { |
|
1110 struct sctp_chunkhdr *chk; |
|
1111 |
|
1112 chk = (struct sctp_chunkhdr *)((caddr_t)phdr + sizeof(*phdr)); |
|
1113 switch (chk->chunk_type) { |
|
1114 case SCTP_ASCONF_ACK: |
|
1115 case SCTP_ASCONF: |
|
1116 sctp_asconf_cleanup(stcb, net); |
|
1117 break; |
|
1118 case SCTP_FORWARD_CUM_TSN: |
|
1119 stcb->asoc.peer_supports_prsctp = 0; |
|
1120 break; |
|
1121 default: |
|
1122 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1123 "Peer does not support chunk type %d(%x)??\n", |
|
1124 chk->chunk_type, (uint32_t) chk->chunk_type); |
|
1125 break; |
|
1126 } |
|
1127 } |
|
1128 |
|
1129 /* |
|
1130 * Skip past the param header and then we will find the param that caused the |
|
1131 * problem. There are a number of param's in a ASCONF OR the prsctp param |
|
1132 * these will turn of specific features. |
|
1133 */ |
|
1134 static void |
|
1135 sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr) |
|
1136 { |
|
1137 struct sctp_paramhdr *pbad; |
|
1138 |
|
1139 pbad = phdr + 1; |
|
1140 switch (ntohs(pbad->param_type)) { |
|
1141 /* pr-sctp draft */ |
|
1142 case SCTP_PRSCTP_SUPPORTED: |
|
1143 stcb->asoc.peer_supports_prsctp = 0; |
|
1144 break; |
|
1145 case SCTP_SUPPORTED_CHUNK_EXT: |
|
1146 break; |
|
1147 /* draft-ietf-tsvwg-addip-sctp */ |
|
1148 case SCTP_HAS_NAT_SUPPORT: |
|
1149 stcb->asoc.peer_supports_nat = 0; |
|
1150 break; |
|
1151 case SCTP_ADD_IP_ADDRESS: |
|
1152 case SCTP_DEL_IP_ADDRESS: |
|
1153 case SCTP_SET_PRIM_ADDR: |
|
1154 stcb->asoc.peer_supports_asconf = 0; |
|
1155 break; |
|
1156 case SCTP_SUCCESS_REPORT: |
|
1157 case SCTP_ERROR_CAUSE_IND: |
|
1158 SCTPDBG(SCTP_DEBUG_INPUT2, "Huh, the peer does not support success? or error cause?\n"); |
|
1159 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1160 "Turning off ASCONF to this strange peer\n"); |
|
1161 stcb->asoc.peer_supports_asconf = 0; |
|
1162 break; |
|
1163 default: |
|
1164 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1165 "Peer does not support param type %d(%x)??\n", |
|
1166 pbad->param_type, (uint32_t) pbad->param_type); |
|
1167 break; |
|
1168 } |
|
1169 } |
|
1170 |
|
1171 static int |
|
1172 sctp_handle_error(struct sctp_chunkhdr *ch, |
|
1173 struct sctp_tcb *stcb, struct sctp_nets *net) |
|
1174 { |
|
1175 int chklen; |
|
1176 struct sctp_paramhdr *phdr; |
|
1177 uint16_t error, error_type; |
|
1178 uint16_t error_len; |
|
1179 struct sctp_association *asoc; |
|
1180 int adjust; |
|
1181 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1182 struct socket *so; |
|
1183 #endif |
|
1184 |
|
1185 /* parse through all of the errors and process */ |
|
1186 asoc = &stcb->asoc; |
|
1187 phdr = (struct sctp_paramhdr *)((caddr_t)ch + |
|
1188 sizeof(struct sctp_chunkhdr)); |
|
1189 chklen = ntohs(ch->chunk_length) - sizeof(struct sctp_chunkhdr); |
|
1190 error = 0; |
|
1191 while ((size_t)chklen >= sizeof(struct sctp_paramhdr)) { |
|
1192 /* Process an Error Cause */ |
|
1193 error_type = ntohs(phdr->param_type); |
|
1194 error_len = ntohs(phdr->param_length); |
|
1195 if ((error_len > chklen) || (error_len == 0)) { |
|
1196 /* invalid param length for this param */ |
|
1197 SCTPDBG(SCTP_DEBUG_INPUT1, "Bogus length in error param- chunk left:%d errorlen:%d\n", |
|
1198 chklen, error_len); |
|
1199 return (0); |
|
1200 } |
|
1201 if (error == 0) { |
|
1202 /* report the first error cause */ |
|
1203 error = error_type; |
|
1204 } |
|
1205 switch (error_type) { |
|
1206 case SCTP_CAUSE_INVALID_STREAM: |
|
1207 case SCTP_CAUSE_MISSING_PARAM: |
|
1208 case SCTP_CAUSE_INVALID_PARAM: |
|
1209 case SCTP_CAUSE_NO_USER_DATA: |
|
1210 SCTPDBG(SCTP_DEBUG_INPUT1, "Software error we got a %d back? We have a bug :/ (or do they?)\n", |
|
1211 error_type); |
|
1212 break; |
|
1213 case SCTP_CAUSE_NAT_COLLIDING_STATE: |
|
1214 SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n", |
|
1215 ch->chunk_flags); |
|
1216 if (sctp_handle_nat_colliding_state(stcb)) { |
|
1217 return (0); |
|
1218 } |
|
1219 break; |
|
1220 case SCTP_CAUSE_NAT_MISSING_STATE: |
|
1221 SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n", |
|
1222 ch->chunk_flags); |
|
1223 if (sctp_handle_nat_missing_state(stcb, net)) { |
|
1224 return (0); |
|
1225 } |
|
1226 break; |
|
1227 case SCTP_CAUSE_STALE_COOKIE: |
|
1228 /* |
|
1229 * We only act if we have echoed a cookie and are |
|
1230 * waiting. |
|
1231 */ |
|
1232 if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) { |
|
1233 int *p; |
|
1234 |
|
1235 p = (int *)((caddr_t)phdr + sizeof(*phdr)); |
|
1236 /* Save the time doubled */ |
|
1237 asoc->cookie_preserve_req = ntohl(*p) << 1; |
|
1238 asoc->stale_cookie_count++; |
|
1239 if (asoc->stale_cookie_count > |
|
1240 asoc->max_init_times) { |
|
1241 sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
1242 /* now free the asoc */ |
|
1243 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1244 so = SCTP_INP_SO(stcb->sctp_ep); |
|
1245 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1246 SCTP_TCB_UNLOCK(stcb); |
|
1247 SCTP_SOCKET_LOCK(so, 1); |
|
1248 SCTP_TCB_LOCK(stcb); |
|
1249 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
1250 #endif |
|
1251 (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, |
|
1252 SCTP_FROM_SCTP_INPUT+SCTP_LOC_11); |
|
1253 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1254 SCTP_SOCKET_UNLOCK(so, 1); |
|
1255 #endif |
|
1256 return (-1); |
|
1257 } |
|
1258 /* blast back to INIT state */ |
|
1259 sctp_toss_old_cookies(stcb, &stcb->asoc); |
|
1260 asoc->state &= ~SCTP_STATE_COOKIE_ECHOED; |
|
1261 asoc->state |= SCTP_STATE_COOKIE_WAIT; |
|
1262 sctp_stop_all_cookie_timers(stcb); |
|
1263 sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); |
|
1264 } |
|
1265 break; |
|
1266 case SCTP_CAUSE_UNRESOLVABLE_ADDR: |
|
1267 /* |
|
1268 * Nothing we can do here, we don't do hostname |
|
1269 * addresses so if the peer does not like my IPv6 |
|
1270 * (or IPv4 for that matter) it does not matter. If |
|
1271 * they don't support that type of address, they can |
|
1272 * NOT possibly get that packet type... i.e. with no |
|
1273 * IPv6 you can't recieve a IPv6 packet. so we can |
|
1274 * safely ignore this one. If we ever added support |
|
1275 * for HOSTNAME Addresses, then we would need to do |
|
1276 * something here. |
|
1277 */ |
|
1278 break; |
|
1279 case SCTP_CAUSE_UNRECOG_CHUNK: |
|
1280 sctp_process_unrecog_chunk(stcb, phdr, net); |
|
1281 break; |
|
1282 case SCTP_CAUSE_UNRECOG_PARAM: |
|
1283 sctp_process_unrecog_param(stcb, phdr); |
|
1284 break; |
|
1285 case SCTP_CAUSE_COOKIE_IN_SHUTDOWN: |
|
1286 /* |
|
1287 * We ignore this since the timer will drive out a |
|
1288 * new cookie anyway and there timer will drive us |
|
1289 * to send a SHUTDOWN_COMPLETE. We can't send one |
|
1290 * here since we don't have their tag. |
|
1291 */ |
|
1292 break; |
|
1293 case SCTP_CAUSE_DELETING_LAST_ADDR: |
|
1294 case SCTP_CAUSE_RESOURCE_SHORTAGE: |
|
1295 case SCTP_CAUSE_DELETING_SRC_ADDR: |
|
1296 /* |
|
1297 * We should NOT get these here, but in a |
|
1298 * ASCONF-ACK. |
|
1299 */ |
|
1300 SCTPDBG(SCTP_DEBUG_INPUT2, "Peer sends ASCONF errors in a Operational Error?<%d>?\n", |
|
1301 error_type); |
|
1302 break; |
|
1303 case SCTP_CAUSE_OUT_OF_RESC: |
|
1304 /* |
|
1305 * And what, pray tell do we do with the fact that |
|
1306 * the peer is out of resources? Not really sure we |
|
1307 * could do anything but abort. I suspect this |
|
1308 * should have came WITH an abort instead of in a |
|
1309 * OP-ERROR. |
|
1310 */ |
|
1311 break; |
|
1312 default: |
|
1313 SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_handle_error: unknown error type = 0x%xh\n", |
|
1314 error_type); |
|
1315 break; |
|
1316 } |
|
1317 adjust = SCTP_SIZE32(error_len); |
|
1318 chklen -= adjust; |
|
1319 phdr = (struct sctp_paramhdr *)((caddr_t)phdr + adjust); |
|
1320 } |
|
1321 sctp_ulp_notify(SCTP_NOTIFY_REMOTE_ERROR, stcb, error, ch, SCTP_SO_NOT_LOCKED); |
|
1322 return (0); |
|
1323 } |
|
1324 |
|
1325 static int |
|
1326 sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, |
|
1327 struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, |
|
1328 struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb, |
|
1329 struct sctp_nets *net, int *abort_no_unlock, |
|
1330 #if defined(__FreeBSD__) |
|
1331 uint8_t use_mflowid, uint32_t mflowid, |
|
1332 #endif |
|
1333 uint32_t vrf_id) |
|
1334 { |
|
1335 struct sctp_init_ack *init_ack; |
|
1336 struct mbuf *op_err; |
|
1337 |
|
1338 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1339 "sctp_handle_init_ack: handling INIT-ACK\n"); |
|
1340 |
|
1341 if (stcb == NULL) { |
|
1342 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
1343 "sctp_handle_init_ack: TCB is null\n"); |
|
1344 return (-1); |
|
1345 } |
|
1346 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_ack_chunk)) { |
|
1347 /* Invalid length */ |
|
1348 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
1349 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
1350 src, dst, sh, op_err, |
|
1351 #if defined(__FreeBSD__) |
|
1352 use_mflowid, mflowid, |
|
1353 #endif |
|
1354 vrf_id, net->port); |
|
1355 *abort_no_unlock = 1; |
|
1356 return (-1); |
|
1357 } |
|
1358 init_ack = &cp->init; |
|
1359 /* validate parameters */ |
|
1360 if (init_ack->initiate_tag == 0) { |
|
1361 /* protocol error... send an abort */ |
|
1362 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
1363 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
1364 src, dst, sh, op_err, |
|
1365 #if defined(__FreeBSD__) |
|
1366 use_mflowid, mflowid, |
|
1367 #endif |
|
1368 vrf_id, net->port); |
|
1369 *abort_no_unlock = 1; |
|
1370 return (-1); |
|
1371 } |
|
1372 if (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) { |
|
1373 /* protocol error... send an abort */ |
|
1374 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
1375 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
1376 src, dst, sh, op_err, |
|
1377 #if defined(__FreeBSD__) |
|
1378 use_mflowid, mflowid, |
|
1379 #endif |
|
1380 vrf_id, net->port); |
|
1381 *abort_no_unlock = 1; |
|
1382 return (-1); |
|
1383 } |
|
1384 if (init_ack->num_inbound_streams == 0) { |
|
1385 /* protocol error... send an abort */ |
|
1386 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
1387 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
1388 src, dst, sh, op_err, |
|
1389 #if defined(__FreeBSD__) |
|
1390 use_mflowid, mflowid, |
|
1391 #endif |
|
1392 vrf_id, net->port); |
|
1393 *abort_no_unlock = 1; |
|
1394 return (-1); |
|
1395 } |
|
1396 if (init_ack->num_outbound_streams == 0) { |
|
1397 /* protocol error... send an abort */ |
|
1398 op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM); |
|
1399 sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, |
|
1400 src, dst, sh, op_err, |
|
1401 #if defined(__FreeBSD__) |
|
1402 use_mflowid, mflowid, |
|
1403 #endif |
|
1404 vrf_id, net->port); |
|
1405 *abort_no_unlock = 1; |
|
1406 return (-1); |
|
1407 } |
|
1408 /* process according to association state... */ |
|
1409 switch (stcb->asoc.state & SCTP_STATE_MASK) { |
|
1410 case SCTP_STATE_COOKIE_WAIT: |
|
1411 /* this is the expected state for this chunk */ |
|
1412 /* process the INIT-ACK parameters */ |
|
1413 if (stcb->asoc.primary_destination->dest_state & |
|
1414 SCTP_ADDR_UNCONFIRMED) { |
|
1415 /* |
|
1416 * The primary is where we sent the INIT, we can |
|
1417 * always consider it confirmed when the INIT-ACK is |
|
1418 * returned. Do this before we load addresses |
|
1419 * though. |
|
1420 */ |
|
1421 stcb->asoc.primary_destination->dest_state &= |
|
1422 ~SCTP_ADDR_UNCONFIRMED; |
|
1423 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, |
|
1424 stcb, 0, (void *)stcb->asoc.primary_destination, SCTP_SO_NOT_LOCKED); |
|
1425 } |
|
1426 if (sctp_process_init_ack(m, iphlen, offset, src, dst, sh, cp, stcb, |
|
1427 net, abort_no_unlock, |
|
1428 #if defined(__FreeBSD__) |
|
1429 use_mflowid, mflowid, |
|
1430 #endif |
|
1431 vrf_id) < 0) { |
|
1432 /* error in parsing parameters */ |
|
1433 return (-1); |
|
1434 } |
|
1435 /* update our state */ |
|
1436 SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n"); |
|
1437 SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_ECHOED); |
|
1438 |
|
1439 /* reset the RTO calc */ |
|
1440 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
1441 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
1442 stcb->asoc.overall_error_count, |
|
1443 0, |
|
1444 SCTP_FROM_SCTP_INPUT, |
|
1445 __LINE__); |
|
1446 } |
|
1447 stcb->asoc.overall_error_count = 0; |
|
1448 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
1449 /* |
|
1450 * collapse the init timer back in case of a exponential |
|
1451 * backoff |
|
1452 */ |
|
1453 sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, stcb->sctp_ep, |
|
1454 stcb, net); |
|
1455 /* |
|
1456 * the send at the end of the inbound data processing will |
|
1457 * cause the cookie to be sent |
|
1458 */ |
|
1459 break; |
|
1460 case SCTP_STATE_SHUTDOWN_SENT: |
|
1461 /* incorrect state... discard */ |
|
1462 break; |
|
1463 case SCTP_STATE_COOKIE_ECHOED: |
|
1464 /* incorrect state... discard */ |
|
1465 break; |
|
1466 case SCTP_STATE_OPEN: |
|
1467 /* incorrect state... discard */ |
|
1468 break; |
|
1469 case SCTP_STATE_EMPTY: |
|
1470 case SCTP_STATE_INUSE: |
|
1471 default: |
|
1472 /* incorrect state... discard */ |
|
1473 return (-1); |
|
1474 break; |
|
1475 } |
|
1476 SCTPDBG(SCTP_DEBUG_INPUT1, "Leaving handle-init-ack end\n"); |
|
1477 return (0); |
|
1478 } |
|
1479 |
|
1480 static struct sctp_tcb * |
|
1481 sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, |
|
1482 struct sockaddr *src, struct sockaddr *dst, |
|
1483 struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, |
|
1484 struct sctp_inpcb *inp, struct sctp_nets **netp, |
|
1485 struct sockaddr *init_src, int *notification, |
|
1486 int auth_skipped, uint32_t auth_offset, uint32_t auth_len, |
|
1487 #if defined(__FreeBSD__) |
|
1488 uint8_t use_mflowid, uint32_t mflowid, |
|
1489 #endif |
|
1490 uint32_t vrf_id, uint16_t port); |
|
1491 |
|
1492 |
|
1493 /* |
|
1494 * handle a state cookie for an existing association m: input packet mbuf |
|
1495 * chain-- assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a |
|
1496 * "split" mbuf and the cookie signature does not exist offset: offset into |
|
1497 * mbuf to the cookie-echo chunk |
|
1498 */ |
|
1499 static struct sctp_tcb * |
|
1500 sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, |
|
1501 struct sockaddr *src, struct sockaddr *dst, |
|
1502 struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, |
|
1503 struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets **netp, |
|
1504 struct sockaddr *init_src, int *notification, |
|
1505 int auth_skipped, uint32_t auth_offset, uint32_t auth_len, |
|
1506 #if defined(__FreeBSD__) |
|
1507 uint8_t use_mflowid, uint32_t mflowid, |
|
1508 #endif |
|
1509 uint32_t vrf_id, uint16_t port) |
|
1510 { |
|
1511 struct sctp_association *asoc; |
|
1512 struct sctp_init_chunk *init_cp, init_buf; |
|
1513 struct sctp_init_ack_chunk *initack_cp, initack_buf; |
|
1514 struct sctp_nets *net; |
|
1515 struct mbuf *op_err; |
|
1516 struct sctp_paramhdr *ph; |
|
1517 int init_offset, initack_offset, i; |
|
1518 int retval; |
|
1519 int spec_flag = 0; |
|
1520 uint32_t how_indx; |
|
1521 |
|
1522 net = *netp; |
|
1523 /* I know that the TCB is non-NULL from the caller */ |
|
1524 asoc = &stcb->asoc; |
|
1525 for (how_indx = 0; how_indx < sizeof(asoc->cookie_how); how_indx++) { |
|
1526 if (asoc->cookie_how[how_indx] == 0) |
|
1527 break; |
|
1528 } |
|
1529 if (how_indx < sizeof(asoc->cookie_how)) { |
|
1530 asoc->cookie_how[how_indx] = 1; |
|
1531 } |
|
1532 if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) { |
|
1533 /* SHUTDOWN came in after sending INIT-ACK */ |
|
1534 sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); |
|
1535 op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
|
1536 0, M_NOWAIT, 1, MT_DATA); |
|
1537 if (op_err == NULL) { |
|
1538 /* FOOBAR */ |
|
1539 return (NULL); |
|
1540 } |
|
1541 /* Set the len */ |
|
1542 SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); |
|
1543 ph = mtod(op_err, struct sctp_paramhdr *); |
|
1544 ph->param_type = htons(SCTP_CAUSE_COOKIE_IN_SHUTDOWN); |
|
1545 ph->param_length = htons(sizeof(struct sctp_paramhdr)); |
|
1546 sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err, |
|
1547 #if defined(__FreeBSD__) |
|
1548 use_mflowid, mflowid, |
|
1549 #endif |
|
1550 vrf_id, net->port); |
|
1551 if (how_indx < sizeof(asoc->cookie_how)) |
|
1552 asoc->cookie_how[how_indx] = 2; |
|
1553 return (NULL); |
|
1554 } |
|
1555 /* |
|
1556 * find and validate the INIT chunk in the cookie (peer's info) the |
|
1557 * INIT should start after the cookie-echo header struct (chunk |
|
1558 * header, state cookie header struct) |
|
1559 */ |
|
1560 init_offset = offset += sizeof(struct sctp_cookie_echo_chunk); |
|
1561 |
|
1562 init_cp = (struct sctp_init_chunk *) |
|
1563 sctp_m_getptr(m, init_offset, sizeof(struct sctp_init_chunk), |
|
1564 (uint8_t *) & init_buf); |
|
1565 if (init_cp == NULL) { |
|
1566 /* could not pull a INIT chunk in cookie */ |
|
1567 return (NULL); |
|
1568 } |
|
1569 if (init_cp->ch.chunk_type != SCTP_INITIATION) { |
|
1570 return (NULL); |
|
1571 } |
|
1572 /* |
|
1573 * find and validate the INIT-ACK chunk in the cookie (my info) the |
|
1574 * INIT-ACK follows the INIT chunk |
|
1575 */ |
|
1576 initack_offset = init_offset + SCTP_SIZE32(ntohs(init_cp->ch.chunk_length)); |
|
1577 initack_cp = (struct sctp_init_ack_chunk *) |
|
1578 sctp_m_getptr(m, initack_offset, sizeof(struct sctp_init_ack_chunk), |
|
1579 (uint8_t *) & initack_buf); |
|
1580 if (initack_cp == NULL) { |
|
1581 /* could not pull INIT-ACK chunk in cookie */ |
|
1582 return (NULL); |
|
1583 } |
|
1584 if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) { |
|
1585 return (NULL); |
|
1586 } |
|
1587 if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && |
|
1588 (ntohl(init_cp->init.initiate_tag) == asoc->peer_vtag)) { |
|
1589 /* |
|
1590 * case D in Section 5.2.4 Table 2: MMAA process accordingly |
|
1591 * to get into the OPEN state |
|
1592 */ |
|
1593 if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) { |
|
1594 /*- |
|
1595 * Opps, this means that we somehow generated two vtag's |
|
1596 * the same. I.e. we did: |
|
1597 * Us Peer |
|
1598 * <---INIT(tag=a)------ |
|
1599 * ----INIT-ACK(tag=t)--> |
|
1600 * ----INIT(tag=t)------> *1 |
|
1601 * <---INIT-ACK(tag=a)--- |
|
1602 * <----CE(tag=t)------------- *2 |
|
1603 * |
|
1604 * At point *1 we should be generating a different |
|
1605 * tag t'. Which means we would throw away the CE and send |
|
1606 * ours instead. Basically this is case C (throw away side). |
|
1607 */ |
|
1608 if (how_indx < sizeof(asoc->cookie_how)) |
|
1609 asoc->cookie_how[how_indx] = 17; |
|
1610 return (NULL); |
|
1611 |
|
1612 } |
|
1613 switch (SCTP_GET_STATE(asoc)) { |
|
1614 case SCTP_STATE_COOKIE_WAIT: |
|
1615 case SCTP_STATE_COOKIE_ECHOED: |
|
1616 /* |
|
1617 * INIT was sent but got a COOKIE_ECHO with the |
|
1618 * correct tags... just accept it...but we must |
|
1619 * process the init so that we can make sure we |
|
1620 * have the right seq no's. |
|
1621 */ |
|
1622 /* First we must process the INIT !! */ |
|
1623 retval = sctp_process_init(init_cp, stcb); |
|
1624 if (retval < 0) { |
|
1625 if (how_indx < sizeof(asoc->cookie_how)) |
|
1626 asoc->cookie_how[how_indx] = 3; |
|
1627 return (NULL); |
|
1628 } |
|
1629 /* we have already processed the INIT so no problem */ |
|
1630 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, |
|
1631 net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_12); |
|
1632 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_13); |
|
1633 /* update current state */ |
|
1634 if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) |
|
1635 SCTP_STAT_INCR_COUNTER32(sctps_activeestab); |
|
1636 else |
|
1637 SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); |
|
1638 |
|
1639 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
1640 if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { |
|
1641 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
1642 stcb->sctp_ep, stcb, asoc->primary_destination); |
|
1643 } |
|
1644 SCTP_STAT_INCR_GAUGE32(sctps_currestab); |
|
1645 sctp_stop_all_cookie_timers(stcb); |
|
1646 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
1647 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && |
|
1648 (inp->sctp_socket->so_qlimit == 0) |
|
1649 ) { |
|
1650 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1651 struct socket *so; |
|
1652 #endif |
|
1653 /* |
|
1654 * Here is where collision would go if we |
|
1655 * did a connect() and instead got a |
|
1656 * init/init-ack/cookie done before the |
|
1657 * init-ack came back.. |
|
1658 */ |
|
1659 stcb->sctp_ep->sctp_flags |= |
|
1660 SCTP_PCB_FLAGS_CONNECTED; |
|
1661 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1662 so = SCTP_INP_SO(stcb->sctp_ep); |
|
1663 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1664 SCTP_TCB_UNLOCK(stcb); |
|
1665 SCTP_SOCKET_LOCK(so, 1); |
|
1666 SCTP_TCB_LOCK(stcb); |
|
1667 atomic_add_int(&stcb->asoc.refcnt, -1); |
|
1668 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
1669 SCTP_SOCKET_UNLOCK(so, 1); |
|
1670 return (NULL); |
|
1671 } |
|
1672 #endif |
|
1673 soisconnected(stcb->sctp_socket); |
|
1674 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1675 SCTP_SOCKET_UNLOCK(so, 1); |
|
1676 #endif |
|
1677 } |
|
1678 /* notify upper layer */ |
|
1679 *notification = SCTP_NOTIFY_ASSOC_UP; |
|
1680 /* |
|
1681 * since we did not send a HB make sure we |
|
1682 * don't double things |
|
1683 */ |
|
1684 net->hb_responded = 1; |
|
1685 net->RTO = sctp_calculate_rto(stcb, asoc, net, |
|
1686 &cookie->time_entered, |
|
1687 sctp_align_unsafe_makecopy, |
|
1688 SCTP_RTT_FROM_NON_DATA); |
|
1689 |
|
1690 if (stcb->asoc.sctp_autoclose_ticks && |
|
1691 (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))) { |
|
1692 sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, |
|
1693 inp, stcb, NULL); |
|
1694 } |
|
1695 break; |
|
1696 default: |
|
1697 /* |
|
1698 * we're in the OPEN state (or beyond), so |
|
1699 * peer must have simply lost the COOKIE-ACK |
|
1700 */ |
|
1701 break; |
|
1702 } /* end switch */ |
|
1703 sctp_stop_all_cookie_timers(stcb); |
|
1704 /* |
|
1705 * We ignore the return code here.. not sure if we should |
|
1706 * somehow abort.. but we do have an existing asoc. This |
|
1707 * really should not fail. |
|
1708 */ |
|
1709 if (sctp_load_addresses_from_init(stcb, m, |
|
1710 init_offset + sizeof(struct sctp_init_chunk), |
|
1711 initack_offset, src, dst, init_src)) { |
|
1712 if (how_indx < sizeof(asoc->cookie_how)) |
|
1713 asoc->cookie_how[how_indx] = 4; |
|
1714 return (NULL); |
|
1715 } |
|
1716 /* respond with a COOKIE-ACK */ |
|
1717 sctp_toss_old_cookies(stcb, asoc); |
|
1718 sctp_send_cookie_ack(stcb); |
|
1719 if (how_indx < sizeof(asoc->cookie_how)) |
|
1720 asoc->cookie_how[how_indx] = 5; |
|
1721 return (stcb); |
|
1722 } |
|
1723 |
|
1724 if (ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag && |
|
1725 ntohl(init_cp->init.initiate_tag) == asoc->peer_vtag && |
|
1726 cookie->tie_tag_my_vtag == 0 && |
|
1727 cookie->tie_tag_peer_vtag == 0) { |
|
1728 /* |
|
1729 * case C in Section 5.2.4 Table 2: XMOO silently discard |
|
1730 */ |
|
1731 if (how_indx < sizeof(asoc->cookie_how)) |
|
1732 asoc->cookie_how[how_indx] = 6; |
|
1733 return (NULL); |
|
1734 } |
|
1735 /* If nat support, and the below and stcb is established, |
|
1736 * send back a ABORT(colliding state) if we are established. |
|
1737 */ |
|
1738 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) && |
|
1739 (asoc->peer_supports_nat) && |
|
1740 ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && |
|
1741 ((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) || |
|
1742 (asoc->peer_vtag == 0)))) { |
|
1743 /* Special case - Peer's support nat. We may have |
|
1744 * two init's that we gave out the same tag on since |
|
1745 * one was not established.. i.e. we get INIT from host-1 |
|
1746 * behind the nat and we respond tag-a, we get a INIT from |
|
1747 * host-2 behind the nat and we get tag-a again. Then we |
|
1748 * bring up host-1 (or 2's) assoc, Then comes the cookie |
|
1749 * from hsot-2 (or 1). Now we have colliding state. We must |
|
1750 * send an abort here with colliding state indication. |
|
1751 */ |
|
1752 op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
|
1753 0, M_NOWAIT, 1, MT_DATA); |
|
1754 if (op_err == NULL) { |
|
1755 /* FOOBAR */ |
|
1756 return (NULL); |
|
1757 } |
|
1758 /* pre-reserve some space */ |
|
1759 #ifdef INET6 |
|
1760 SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); |
|
1761 #else |
|
1762 SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); |
|
1763 #endif |
|
1764 SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); |
|
1765 SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); |
|
1766 /* Set the len */ |
|
1767 SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); |
|
1768 ph = mtod(op_err, struct sctp_paramhdr *); |
|
1769 ph->param_type = htons(SCTP_CAUSE_NAT_COLLIDING_STATE); |
|
1770 ph->param_length = htons(sizeof(struct sctp_paramhdr)); |
|
1771 sctp_send_abort(m, iphlen, src, dst, sh, 0, op_err, |
|
1772 #if defined(__FreeBSD__) |
|
1773 use_mflowid, mflowid, |
|
1774 #endif |
|
1775 vrf_id, port); |
|
1776 return (NULL); |
|
1777 } |
|
1778 if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) && |
|
1779 ((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) || |
|
1780 (asoc->peer_vtag == 0))) { |
|
1781 /* |
|
1782 * case B in Section 5.2.4 Table 2: MXAA or MOAA my info |
|
1783 * should be ok, re-accept peer info |
|
1784 */ |
|
1785 if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) { |
|
1786 /* Extension of case C. |
|
1787 * If we hit this, then the random number |
|
1788 * generator returned the same vtag when we |
|
1789 * first sent our INIT-ACK and when we later sent |
|
1790 * our INIT. The side with the seq numbers that are |
|
1791 * different will be the one that normnally would |
|
1792 * have hit case C. This in effect "extends" our vtags |
|
1793 * in this collision case to be 64 bits. The same collision |
|
1794 * could occur aka you get both vtag and seq number the |
|
1795 * same twice in a row.. but is much less likely. If it |
|
1796 * did happen then we would proceed through and bring |
|
1797 * up the assoc.. we may end up with the wrong stream |
|
1798 * setup however.. which would be bad.. but there is |
|
1799 * no way to tell.. until we send on a stream that does |
|
1800 * not exist :-) |
|
1801 */ |
|
1802 if (how_indx < sizeof(asoc->cookie_how)) |
|
1803 asoc->cookie_how[how_indx] = 7; |
|
1804 |
|
1805 return (NULL); |
|
1806 } |
|
1807 if (how_indx < sizeof(asoc->cookie_how)) |
|
1808 asoc->cookie_how[how_indx] = 8; |
|
1809 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_14); |
|
1810 sctp_stop_all_cookie_timers(stcb); |
|
1811 /* |
|
1812 * since we did not send a HB make sure we don't double |
|
1813 * things |
|
1814 */ |
|
1815 net->hb_responded = 1; |
|
1816 if (stcb->asoc.sctp_autoclose_ticks && |
|
1817 sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { |
|
1818 sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, |
|
1819 NULL); |
|
1820 } |
|
1821 asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); |
|
1822 asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); |
|
1823 |
|
1824 if (ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) { |
|
1825 /* Ok the peer probably discarded our |
|
1826 * data (if we echoed a cookie+data). So anything |
|
1827 * on the sent_queue should be marked for |
|
1828 * retransmit, we may not get something to |
|
1829 * kick us so it COULD still take a timeout |
|
1830 * to move these.. but it can't hurt to mark them. |
|
1831 */ |
|
1832 struct sctp_tmit_chunk *chk; |
|
1833 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { |
|
1834 if (chk->sent < SCTP_DATAGRAM_RESEND) { |
|
1835 chk->sent = SCTP_DATAGRAM_RESEND; |
|
1836 sctp_flight_size_decrease(chk); |
|
1837 sctp_total_flight_decrease(stcb, chk); |
|
1838 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
1839 spec_flag++; |
|
1840 } |
|
1841 } |
|
1842 |
|
1843 } |
|
1844 /* process the INIT info (peer's info) */ |
|
1845 retval = sctp_process_init(init_cp, stcb); |
|
1846 if (retval < 0) { |
|
1847 if (how_indx < sizeof(asoc->cookie_how)) |
|
1848 asoc->cookie_how[how_indx] = 9; |
|
1849 return (NULL); |
|
1850 } |
|
1851 if (sctp_load_addresses_from_init(stcb, m, |
|
1852 init_offset + sizeof(struct sctp_init_chunk), |
|
1853 initack_offset, src, dst, init_src)) { |
|
1854 if (how_indx < sizeof(asoc->cookie_how)) |
|
1855 asoc->cookie_how[how_indx] = 10; |
|
1856 return (NULL); |
|
1857 } |
|
1858 if ((asoc->state & SCTP_STATE_COOKIE_WAIT) || |
|
1859 (asoc->state & SCTP_STATE_COOKIE_ECHOED)) { |
|
1860 *notification = SCTP_NOTIFY_ASSOC_UP; |
|
1861 |
|
1862 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
1863 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && |
|
1864 (inp->sctp_socket->so_qlimit == 0)) { |
|
1865 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1866 struct socket *so; |
|
1867 #endif |
|
1868 stcb->sctp_ep->sctp_flags |= |
|
1869 SCTP_PCB_FLAGS_CONNECTED; |
|
1870 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1871 so = SCTP_INP_SO(stcb->sctp_ep); |
|
1872 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1873 SCTP_TCB_UNLOCK(stcb); |
|
1874 SCTP_SOCKET_LOCK(so, 1); |
|
1875 SCTP_TCB_LOCK(stcb); |
|
1876 atomic_add_int(&stcb->asoc.refcnt, -1); |
|
1877 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
1878 SCTP_SOCKET_UNLOCK(so, 1); |
|
1879 return (NULL); |
|
1880 } |
|
1881 #endif |
|
1882 soisconnected(stcb->sctp_socket); |
|
1883 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1884 SCTP_SOCKET_UNLOCK(so, 1); |
|
1885 #endif |
|
1886 } |
|
1887 if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) |
|
1888 SCTP_STAT_INCR_COUNTER32(sctps_activeestab); |
|
1889 else |
|
1890 SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); |
|
1891 SCTP_STAT_INCR_GAUGE32(sctps_currestab); |
|
1892 } else if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { |
|
1893 SCTP_STAT_INCR_COUNTER32(sctps_restartestab); |
|
1894 } else { |
|
1895 SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); |
|
1896 } |
|
1897 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
1898 if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { |
|
1899 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
1900 stcb->sctp_ep, stcb, asoc->primary_destination); |
|
1901 } |
|
1902 sctp_stop_all_cookie_timers(stcb); |
|
1903 sctp_toss_old_cookies(stcb, asoc); |
|
1904 sctp_send_cookie_ack(stcb); |
|
1905 if (spec_flag) { |
|
1906 /* only if we have retrans set do we do this. What |
|
1907 * this call does is get only the COOKIE-ACK out |
|
1908 * and then when we return the normal call to |
|
1909 * sctp_chunk_output will get the retrans out |
|
1910 * behind this. |
|
1911 */ |
|
1912 sctp_chunk_output(inp,stcb, SCTP_OUTPUT_FROM_COOKIE_ACK, SCTP_SO_NOT_LOCKED); |
|
1913 } |
|
1914 if (how_indx < sizeof(asoc->cookie_how)) |
|
1915 asoc->cookie_how[how_indx] = 11; |
|
1916 |
|
1917 return (stcb); |
|
1918 } |
|
1919 if ((ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag && |
|
1920 ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) && |
|
1921 cookie->tie_tag_my_vtag == asoc->my_vtag_nonce && |
|
1922 cookie->tie_tag_peer_vtag == asoc->peer_vtag_nonce && |
|
1923 cookie->tie_tag_peer_vtag != 0) { |
|
1924 struct sctpasochead *head; |
|
1925 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1926 struct socket *so; |
|
1927 #endif |
|
1928 |
|
1929 if (asoc->peer_supports_nat) { |
|
1930 /* This is a gross gross hack. |
|
1931 * Just call the cookie_new code since we |
|
1932 * are allowing a duplicate association. |
|
1933 * I hope this works... |
|
1934 */ |
|
1935 return (sctp_process_cookie_new(m, iphlen, offset, src, dst, |
|
1936 sh, cookie, cookie_len, |
|
1937 inp, netp, init_src,notification, |
|
1938 auth_skipped, auth_offset, auth_len, |
|
1939 #if defined(__FreeBSD__) |
|
1940 use_mflowid, mflowid, |
|
1941 #endif |
|
1942 vrf_id, port)); |
|
1943 } |
|
1944 /* |
|
1945 * case A in Section 5.2.4 Table 2: XXMM (peer restarted) |
|
1946 */ |
|
1947 /* temp code */ |
|
1948 if (how_indx < sizeof(asoc->cookie_how)) |
|
1949 asoc->cookie_how[how_indx] = 12; |
|
1950 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_15); |
|
1951 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_16); |
|
1952 |
|
1953 /* notify upper layer */ |
|
1954 *notification = SCTP_NOTIFY_ASSOC_RESTART; |
|
1955 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
1956 if ((SCTP_GET_STATE(asoc) != SCTP_STATE_OPEN) && |
|
1957 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
|
1958 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) { |
|
1959 SCTP_STAT_INCR_GAUGE32(sctps_currestab); |
|
1960 } |
|
1961 if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { |
|
1962 SCTP_STAT_INCR_GAUGE32(sctps_restartestab); |
|
1963 } else if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { |
|
1964 SCTP_STAT_INCR_GAUGE32(sctps_collisionestab); |
|
1965 } |
|
1966 if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { |
|
1967 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
1968 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
1969 stcb->sctp_ep, stcb, asoc->primary_destination); |
|
1970 |
|
1971 } else if (!(asoc->state & SCTP_STATE_SHUTDOWN_SENT)) { |
|
1972 /* move to OPEN state, if not in SHUTDOWN_SENT */ |
|
1973 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
1974 } |
|
1975 asoc->pre_open_streams = |
|
1976 ntohs(initack_cp->init.num_outbound_streams); |
|
1977 asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn); |
|
1978 asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number; |
|
1979 asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; |
|
1980 |
|
1981 asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1; |
|
1982 |
|
1983 asoc->str_reset_seq_in = asoc->init_seq_number; |
|
1984 |
|
1985 asoc->advanced_peer_ack_point = asoc->last_acked_seq; |
|
1986 if (asoc->mapping_array) { |
|
1987 memset(asoc->mapping_array, 0, |
|
1988 asoc->mapping_array_size); |
|
1989 } |
|
1990 if (asoc->nr_mapping_array) { |
|
1991 memset(asoc->nr_mapping_array, 0, |
|
1992 asoc->mapping_array_size); |
|
1993 } |
|
1994 SCTP_TCB_UNLOCK(stcb); |
|
1995 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
1996 so = SCTP_INP_SO(stcb->sctp_ep); |
|
1997 SCTP_SOCKET_LOCK(so, 1); |
|
1998 #endif |
|
1999 SCTP_INP_INFO_WLOCK(); |
|
2000 SCTP_INP_WLOCK(stcb->sctp_ep); |
|
2001 SCTP_TCB_LOCK(stcb); |
|
2002 atomic_add_int(&stcb->asoc.refcnt, -1); |
|
2003 /* send up all the data */ |
|
2004 SCTP_TCB_SEND_LOCK(stcb); |
|
2005 |
|
2006 sctp_report_all_outbound(stcb, 0, 1, SCTP_SO_LOCKED); |
|
2007 for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
|
2008 stcb->asoc.strmout[i].chunks_on_queues = 0; |
|
2009 stcb->asoc.strmout[i].stream_no = i; |
|
2010 stcb->asoc.strmout[i].next_sequence_send = 0; |
|
2011 stcb->asoc.strmout[i].last_msg_incomplete = 0; |
|
2012 } |
|
2013 /* process the INIT-ACK info (my info) */ |
|
2014 asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); |
|
2015 asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); |
|
2016 |
|
2017 /* pull from vtag hash */ |
|
2018 LIST_REMOVE(stcb, sctp_asocs); |
|
2019 /* re-insert to new vtag position */ |
|
2020 head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, |
|
2021 SCTP_BASE_INFO(hashasocmark))]; |
|
2022 /* |
|
2023 * put it in the bucket in the vtag hash of assoc's for the |
|
2024 * system |
|
2025 */ |
|
2026 LIST_INSERT_HEAD(head, stcb, sctp_asocs); |
|
2027 |
|
2028 SCTP_TCB_SEND_UNLOCK(stcb); |
|
2029 SCTP_INP_WUNLOCK(stcb->sctp_ep); |
|
2030 SCTP_INP_INFO_WUNLOCK(); |
|
2031 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2032 SCTP_SOCKET_UNLOCK(so, 1); |
|
2033 #endif |
|
2034 asoc->total_flight = 0; |
|
2035 asoc->total_flight_count = 0; |
|
2036 /* process the INIT info (peer's info) */ |
|
2037 retval = sctp_process_init(init_cp, stcb); |
|
2038 if (retval < 0) { |
|
2039 if (how_indx < sizeof(asoc->cookie_how)) |
|
2040 asoc->cookie_how[how_indx] = 13; |
|
2041 |
|
2042 return (NULL); |
|
2043 } |
|
2044 /* |
|
2045 * since we did not send a HB make sure we don't double |
|
2046 * things |
|
2047 */ |
|
2048 net->hb_responded = 1; |
|
2049 |
|
2050 if (sctp_load_addresses_from_init(stcb, m, |
|
2051 init_offset + sizeof(struct sctp_init_chunk), |
|
2052 initack_offset, src, dst, init_src)) { |
|
2053 if (how_indx < sizeof(asoc->cookie_how)) |
|
2054 asoc->cookie_how[how_indx] = 14; |
|
2055 |
|
2056 return (NULL); |
|
2057 } |
|
2058 /* respond with a COOKIE-ACK */ |
|
2059 sctp_stop_all_cookie_timers(stcb); |
|
2060 sctp_toss_old_cookies(stcb, asoc); |
|
2061 sctp_send_cookie_ack(stcb); |
|
2062 if (how_indx < sizeof(asoc->cookie_how)) |
|
2063 asoc->cookie_how[how_indx] = 15; |
|
2064 |
|
2065 return (stcb); |
|
2066 } |
|
2067 if (how_indx < sizeof(asoc->cookie_how)) |
|
2068 asoc->cookie_how[how_indx] = 16; |
|
2069 /* all other cases... */ |
|
2070 return (NULL); |
|
2071 } |
|
2072 |
|
2073 |
|
2074 /* |
|
2075 * handle a state cookie for a new association m: input packet mbuf chain-- |
|
2076 * assumes a pullup on IP/SCTP/COOKIE-ECHO chunk note: this is a "split" mbuf |
|
2077 * and the cookie signature does not exist offset: offset into mbuf to the |
|
2078 * cookie-echo chunk length: length of the cookie chunk to: where the init |
|
2079 * was from returns a new TCB |
|
2080 */ |
|
2081 static struct sctp_tcb * |
|
2082 sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, |
|
2083 struct sockaddr *src, struct sockaddr *dst, |
|
2084 struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len, |
|
2085 struct sctp_inpcb *inp, struct sctp_nets **netp, |
|
2086 struct sockaddr *init_src, int *notification, |
|
2087 int auth_skipped, uint32_t auth_offset, uint32_t auth_len, |
|
2088 #if defined(__FreeBSD__) |
|
2089 uint8_t use_mflowid, uint32_t mflowid, |
|
2090 #endif |
|
2091 uint32_t vrf_id, uint16_t port) |
|
2092 { |
|
2093 struct sctp_tcb *stcb; |
|
2094 struct sctp_init_chunk *init_cp, init_buf; |
|
2095 struct sctp_init_ack_chunk *initack_cp, initack_buf; |
|
2096 struct sockaddr_storage sa_store; |
|
2097 struct sockaddr *initack_src = (struct sockaddr *)&sa_store; |
|
2098 struct sctp_association *asoc; |
|
2099 int init_offset, initack_offset, initack_limit; |
|
2100 int retval; |
|
2101 int error = 0; |
|
2102 uint8_t auth_chunk_buf[SCTP_PARAM_BUFFER_SIZE]; |
|
2103 #ifdef INET |
|
2104 struct sockaddr_in *sin; |
|
2105 #endif |
|
2106 #ifdef INET6 |
|
2107 struct sockaddr_in6 *sin6; |
|
2108 #endif |
|
2109 #if defined(__Userspace__) |
|
2110 struct sockaddr_conn *sconn; |
|
2111 #endif |
|
2112 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2113 struct socket *so; |
|
2114 |
|
2115 so = SCTP_INP_SO(inp); |
|
2116 #endif |
|
2117 |
|
2118 /* |
|
2119 * find and validate the INIT chunk in the cookie (peer's info) the |
|
2120 * INIT should start after the cookie-echo header struct (chunk |
|
2121 * header, state cookie header struct) |
|
2122 */ |
|
2123 init_offset = offset + sizeof(struct sctp_cookie_echo_chunk); |
|
2124 init_cp = (struct sctp_init_chunk *) |
|
2125 sctp_m_getptr(m, init_offset, sizeof(struct sctp_init_chunk), |
|
2126 (uint8_t *) & init_buf); |
|
2127 if (init_cp == NULL) { |
|
2128 /* could not pull a INIT chunk in cookie */ |
|
2129 SCTPDBG(SCTP_DEBUG_INPUT1, |
|
2130 "process_cookie_new: could not pull INIT chunk hdr\n"); |
|
2131 return (NULL); |
|
2132 } |
|
2133 if (init_cp->ch.chunk_type != SCTP_INITIATION) { |
|
2134 SCTPDBG(SCTP_DEBUG_INPUT1, "HUH? process_cookie_new: could not find INIT chunk!\n"); |
|
2135 return (NULL); |
|
2136 } |
|
2137 initack_offset = init_offset + SCTP_SIZE32(ntohs(init_cp->ch.chunk_length)); |
|
2138 /* |
|
2139 * find and validate the INIT-ACK chunk in the cookie (my info) the |
|
2140 * INIT-ACK follows the INIT chunk |
|
2141 */ |
|
2142 initack_cp = (struct sctp_init_ack_chunk *) |
|
2143 sctp_m_getptr(m, initack_offset, sizeof(struct sctp_init_ack_chunk), |
|
2144 (uint8_t *) & initack_buf); |
|
2145 if (initack_cp == NULL) { |
|
2146 /* could not pull INIT-ACK chunk in cookie */ |
|
2147 SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: could not pull INIT-ACK chunk hdr\n"); |
|
2148 return (NULL); |
|
2149 } |
|
2150 if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) { |
|
2151 return (NULL); |
|
2152 } |
|
2153 /* |
|
2154 * NOTE: We can't use the INIT_ACK's chk_length to determine the |
|
2155 * "initack_limit" value. This is because the chk_length field |
|
2156 * includes the length of the cookie, but the cookie is omitted when |
|
2157 * the INIT and INIT_ACK are tacked onto the cookie... |
|
2158 */ |
|
2159 initack_limit = offset + cookie_len; |
|
2160 |
|
2161 /* |
|
2162 * now that we know the INIT/INIT-ACK are in place, create a new TCB |
|
2163 * and popluate |
|
2164 */ |
|
2165 |
|
2166 /* |
|
2167 * Here we do a trick, we set in NULL for the proc/thread argument. We |
|
2168 * do this since in effect we only use the p argument when |
|
2169 * the socket is unbound and we must do an implicit bind. |
|
2170 * Since we are getting a cookie, we cannot be unbound. |
|
2171 */ |
|
2172 stcb = sctp_aloc_assoc(inp, init_src, &error, |
|
2173 ntohl(initack_cp->init.initiate_tag), vrf_id, |
|
2174 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
2175 (struct thread *)NULL |
|
2176 #elif defined(__Windows__) |
|
2177 (PKTHREAD)NULL |
|
2178 #else |
|
2179 (struct proc *)NULL |
|
2180 #endif |
|
2181 ); |
|
2182 if (stcb == NULL) { |
|
2183 struct mbuf *op_err; |
|
2184 |
|
2185 /* memory problem? */ |
|
2186 SCTPDBG(SCTP_DEBUG_INPUT1, |
|
2187 "process_cookie_new: no room for another TCB!\n"); |
|
2188 op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); |
|
2189 |
|
2190 sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen, |
|
2191 src, dst, sh, op_err, |
|
2192 #if defined(__FreeBSD__) |
|
2193 use_mflowid, mflowid, |
|
2194 #endif |
|
2195 vrf_id, port); |
|
2196 return (NULL); |
|
2197 } |
|
2198 /* get the correct sctp_nets */ |
|
2199 if (netp) |
|
2200 *netp = sctp_findnet(stcb, init_src); |
|
2201 |
|
2202 asoc = &stcb->asoc; |
|
2203 /* get scope variables out of cookie */ |
|
2204 asoc->scope.ipv4_local_scope = cookie->ipv4_scope; |
|
2205 asoc->scope.site_scope = cookie->site_scope; |
|
2206 asoc->scope.local_scope = cookie->local_scope; |
|
2207 asoc->scope.loopback_scope = cookie->loopback_scope; |
|
2208 |
|
2209 #if defined(__Userspace__) |
|
2210 if ((asoc->scope.ipv4_addr_legal != cookie->ipv4_addr_legal) || |
|
2211 (asoc->scope.ipv6_addr_legal != cookie->ipv6_addr_legal) || |
|
2212 (asoc->scope.conn_addr_legal != cookie->conn_addr_legal)) { |
|
2213 #else |
|
2214 if ((asoc->scope.ipv4_addr_legal != cookie->ipv4_addr_legal) || |
|
2215 (asoc->scope.ipv6_addr_legal != cookie->ipv6_addr_legal)) { |
|
2216 #endif |
|
2217 struct mbuf *op_err; |
|
2218 |
|
2219 /* |
|
2220 * Houston we have a problem. The EP changed while the |
|
2221 * cookie was in flight. Only recourse is to abort the |
|
2222 * association. |
|
2223 */ |
|
2224 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2225 op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); |
|
2226 sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen, |
|
2227 src, dst, sh, op_err, |
|
2228 #if defined(__FreeBSD__) |
|
2229 use_mflowid, mflowid, |
|
2230 #endif |
|
2231 vrf_id, port); |
|
2232 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2233 SCTP_TCB_UNLOCK(stcb); |
|
2234 SCTP_SOCKET_LOCK(so, 1); |
|
2235 SCTP_TCB_LOCK(stcb); |
|
2236 #endif |
|
2237 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, |
|
2238 SCTP_FROM_SCTP_INPUT+SCTP_LOC_16); |
|
2239 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2240 SCTP_SOCKET_UNLOCK(so, 1); |
|
2241 #endif |
|
2242 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2243 return (NULL); |
|
2244 } |
|
2245 /* process the INIT-ACK info (my info) */ |
|
2246 asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); |
|
2247 asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); |
|
2248 asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); |
|
2249 asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn); |
|
2250 asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number; |
|
2251 asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; |
|
2252 asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1; |
|
2253 asoc->str_reset_seq_in = asoc->init_seq_number; |
|
2254 |
|
2255 asoc->advanced_peer_ack_point = asoc->last_acked_seq; |
|
2256 |
|
2257 /* process the INIT info (peer's info) */ |
|
2258 if (netp) |
|
2259 retval = sctp_process_init(init_cp, stcb); |
|
2260 else |
|
2261 retval = 0; |
|
2262 if (retval < 0) { |
|
2263 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2264 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2265 SCTP_TCB_UNLOCK(stcb); |
|
2266 SCTP_SOCKET_LOCK(so, 1); |
|
2267 SCTP_TCB_LOCK(stcb); |
|
2268 #endif |
|
2269 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_16); |
|
2270 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2271 SCTP_SOCKET_UNLOCK(so, 1); |
|
2272 #endif |
|
2273 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2274 return (NULL); |
|
2275 } |
|
2276 /* load all addresses */ |
|
2277 if (sctp_load_addresses_from_init(stcb, m, |
|
2278 init_offset + sizeof(struct sctp_init_chunk), initack_offset, |
|
2279 src, dst, init_src)) { |
|
2280 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2281 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2282 SCTP_TCB_UNLOCK(stcb); |
|
2283 SCTP_SOCKET_LOCK(so, 1); |
|
2284 SCTP_TCB_LOCK(stcb); |
|
2285 #endif |
|
2286 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_17); |
|
2287 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2288 SCTP_SOCKET_UNLOCK(so, 1); |
|
2289 #endif |
|
2290 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2291 return (NULL); |
|
2292 } |
|
2293 /* |
|
2294 * verify any preceding AUTH chunk that was skipped |
|
2295 */ |
|
2296 /* pull the local authentication parameters from the cookie/init-ack */ |
|
2297 sctp_auth_get_cookie_params(stcb, m, |
|
2298 initack_offset + sizeof(struct sctp_init_ack_chunk), |
|
2299 initack_limit - (initack_offset + sizeof(struct sctp_init_ack_chunk))); |
|
2300 if (auth_skipped) { |
|
2301 struct sctp_auth_chunk *auth; |
|
2302 |
|
2303 auth = (struct sctp_auth_chunk *) |
|
2304 sctp_m_getptr(m, auth_offset, auth_len, auth_chunk_buf); |
|
2305 if ((auth == NULL) || sctp_handle_auth(stcb, auth, m, auth_offset)) { |
|
2306 /* auth HMAC failed, dump the assoc and packet */ |
|
2307 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
2308 "COOKIE-ECHO: AUTH failed\n"); |
|
2309 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2310 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2311 SCTP_TCB_UNLOCK(stcb); |
|
2312 SCTP_SOCKET_LOCK(so, 1); |
|
2313 SCTP_TCB_LOCK(stcb); |
|
2314 #endif |
|
2315 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_18); |
|
2316 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2317 SCTP_SOCKET_UNLOCK(so, 1); |
|
2318 #endif |
|
2319 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2320 return (NULL); |
|
2321 } else { |
|
2322 /* remaining chunks checked... good to go */ |
|
2323 stcb->asoc.authenticated = 1; |
|
2324 } |
|
2325 } |
|
2326 /* update current state */ |
|
2327 SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); |
|
2328 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
2329 if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { |
|
2330 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
2331 stcb->sctp_ep, stcb, asoc->primary_destination); |
|
2332 } |
|
2333 sctp_stop_all_cookie_timers(stcb); |
|
2334 SCTP_STAT_INCR_COUNTER32(sctps_passiveestab); |
|
2335 SCTP_STAT_INCR_GAUGE32(sctps_currestab); |
|
2336 |
|
2337 /* |
|
2338 * if we're doing ASCONFs, check to see if we have any new local |
|
2339 * addresses that need to get added to the peer (eg. addresses |
|
2340 * changed while cookie echo in flight). This needs to be done |
|
2341 * after we go to the OPEN state to do the correct asconf |
|
2342 * processing. else, make sure we have the correct addresses in our |
|
2343 * lists |
|
2344 */ |
|
2345 |
|
2346 /* warning, we re-use sin, sin6, sa_store here! */ |
|
2347 /* pull in local_address (our "from" address) */ |
|
2348 switch (cookie->laddr_type) { |
|
2349 #ifdef INET |
|
2350 case SCTP_IPV4_ADDRESS: |
|
2351 /* source addr is IPv4 */ |
|
2352 sin = (struct sockaddr_in *)initack_src; |
|
2353 memset(sin, 0, sizeof(*sin)); |
|
2354 sin->sin_family = AF_INET; |
|
2355 #ifdef HAVE_SIN_LEN |
|
2356 sin->sin_len = sizeof(struct sockaddr_in); |
|
2357 #endif |
|
2358 sin->sin_addr.s_addr = cookie->laddress[0]; |
|
2359 break; |
|
2360 #endif |
|
2361 #ifdef INET6 |
|
2362 case SCTP_IPV6_ADDRESS: |
|
2363 /* source addr is IPv6 */ |
|
2364 sin6 = (struct sockaddr_in6 *)initack_src; |
|
2365 memset(sin6, 0, sizeof(*sin6)); |
|
2366 sin6->sin6_family = AF_INET6; |
|
2367 #ifdef HAVE_SIN6_LEN |
|
2368 sin6->sin6_len = sizeof(struct sockaddr_in6); |
|
2369 #endif |
|
2370 sin6->sin6_scope_id = cookie->scope_id; |
|
2371 memcpy(&sin6->sin6_addr, cookie->laddress, |
|
2372 sizeof(sin6->sin6_addr)); |
|
2373 break; |
|
2374 #endif |
|
2375 #if defined(__Userspace__) |
|
2376 case SCTP_CONN_ADDRESS: |
|
2377 /* source addr is IPv4 */ |
|
2378 sconn = (struct sockaddr_conn *)initack_src; |
|
2379 memset(sconn, 0, sizeof(struct sockaddr_conn)); |
|
2380 sconn->sconn_family = AF_CONN; |
|
2381 #ifdef HAVE_SCONN_LEN |
|
2382 sconn->sconn_len = sizeof(struct sockaddr_conn); |
|
2383 #endif |
|
2384 memcpy(&sconn->sconn_addr, cookie->laddress, sizeof(void *)); |
|
2385 break; |
|
2386 #endif |
|
2387 default: |
|
2388 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2389 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2390 SCTP_TCB_UNLOCK(stcb); |
|
2391 SCTP_SOCKET_LOCK(so, 1); |
|
2392 SCTP_TCB_LOCK(stcb); |
|
2393 #endif |
|
2394 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_19); |
|
2395 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2396 SCTP_SOCKET_UNLOCK(so, 1); |
|
2397 #endif |
|
2398 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2399 return (NULL); |
|
2400 } |
|
2401 |
|
2402 /* set up to notify upper layer */ |
|
2403 *notification = SCTP_NOTIFY_ASSOC_UP; |
|
2404 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2405 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && |
|
2406 (inp->sctp_socket->so_qlimit == 0)) { |
|
2407 /* |
|
2408 * This is an endpoint that called connect() how it got a |
|
2409 * cookie that is NEW is a bit of a mystery. It must be that |
|
2410 * the INIT was sent, but before it got there.. a complete |
|
2411 * INIT/INIT-ACK/COOKIE arrived. But of course then it |
|
2412 * should have went to the other code.. not here.. oh well.. |
|
2413 * a bit of protection is worth having.. |
|
2414 */ |
|
2415 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
2416 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2417 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
2418 SCTP_TCB_UNLOCK(stcb); |
|
2419 SCTP_SOCKET_LOCK(so, 1); |
|
2420 SCTP_TCB_LOCK(stcb); |
|
2421 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
2422 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
2423 SCTP_SOCKET_UNLOCK(so, 1); |
|
2424 return (NULL); |
|
2425 } |
|
2426 #endif |
|
2427 soisconnected(stcb->sctp_socket); |
|
2428 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2429 SCTP_SOCKET_UNLOCK(so, 1); |
|
2430 #endif |
|
2431 } else if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
2432 (inp->sctp_socket->so_qlimit)) { |
|
2433 /* |
|
2434 * We don't want to do anything with this one. Since it is |
|
2435 * the listening guy. The timer will get started for |
|
2436 * accepted connections in the caller. |
|
2437 */ |
|
2438 ; |
|
2439 } |
|
2440 /* since we did not send a HB make sure we don't double things */ |
|
2441 if ((netp) && (*netp)) |
|
2442 (*netp)->hb_responded = 1; |
|
2443 |
|
2444 if (stcb->asoc.sctp_autoclose_ticks && |
|
2445 sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { |
|
2446 sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); |
|
2447 } |
|
2448 /* calculate the RTT */ |
|
2449 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
2450 if ((netp) && (*netp)) { |
|
2451 (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp, |
|
2452 &cookie->time_entered, sctp_align_unsafe_makecopy, |
|
2453 SCTP_RTT_FROM_NON_DATA); |
|
2454 } |
|
2455 /* respond with a COOKIE-ACK */ |
|
2456 sctp_send_cookie_ack(stcb); |
|
2457 |
|
2458 /* |
|
2459 * check the address lists for any ASCONFs that need to be sent |
|
2460 * AFTER the cookie-ack is sent |
|
2461 */ |
|
2462 sctp_check_address_list(stcb, m, |
|
2463 initack_offset + sizeof(struct sctp_init_ack_chunk), |
|
2464 initack_limit - (initack_offset + sizeof(struct sctp_init_ack_chunk)), |
|
2465 initack_src, cookie->local_scope, cookie->site_scope, |
|
2466 cookie->ipv4_scope, cookie->loopback_scope); |
|
2467 |
|
2468 |
|
2469 return (stcb); |
|
2470 } |
|
2471 |
|
2472 /* |
|
2473 * CODE LIKE THIS NEEDS TO RUN IF the peer supports the NAT extension, i.e |
|
2474 * we NEED to make sure we are not already using the vtag. If so we |
|
2475 * need to send back an ABORT-TRY-AGAIN-WITH-NEW-TAG No middle box bit! |
|
2476 head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, |
|
2477 SCTP_BASE_INFO(hashasocmark))]; |
|
2478 LIST_FOREACH(stcb, head, sctp_asocs) { |
|
2479 if ((stcb->asoc.my_vtag == tag) && (stcb->rport == rport) && (inp == stcb->sctp_ep)) { |
|
2480 -- SEND ABORT - TRY AGAIN -- |
|
2481 } |
|
2482 } |
|
2483 */ |
|
2484 |
|
2485 /* |
|
2486 * handles a COOKIE-ECHO message stcb: modified to either a new or left as |
|
2487 * existing (non-NULL) TCB |
|
2488 */ |
|
2489 static struct mbuf * |
|
2490 sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, |
|
2491 struct sockaddr *src, struct sockaddr *dst, |
|
2492 struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp, |
|
2493 struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp, |
|
2494 int auth_skipped, uint32_t auth_offset, uint32_t auth_len, |
|
2495 struct sctp_tcb **locked_tcb, |
|
2496 #if defined(__FreeBSD__) |
|
2497 uint8_t use_mflowid, uint32_t mflowid, |
|
2498 #endif |
|
2499 uint32_t vrf_id, uint16_t port) |
|
2500 { |
|
2501 struct sctp_state_cookie *cookie; |
|
2502 struct sctp_tcb *l_stcb = *stcb; |
|
2503 struct sctp_inpcb *l_inp; |
|
2504 struct sockaddr *to; |
|
2505 struct sctp_pcb *ep; |
|
2506 struct mbuf *m_sig; |
|
2507 uint8_t calc_sig[SCTP_SIGNATURE_SIZE], tmp_sig[SCTP_SIGNATURE_SIZE]; |
|
2508 uint8_t *sig; |
|
2509 uint8_t cookie_ok = 0; |
|
2510 unsigned int sig_offset, cookie_offset; |
|
2511 unsigned int cookie_len; |
|
2512 struct timeval now; |
|
2513 struct timeval time_expires; |
|
2514 int notification = 0; |
|
2515 struct sctp_nets *netl; |
|
2516 int had_a_existing_tcb = 0; |
|
2517 int send_int_conf = 0; |
|
2518 #ifdef INET |
|
2519 struct sockaddr_in sin; |
|
2520 #endif |
|
2521 #ifdef INET6 |
|
2522 struct sockaddr_in6 sin6; |
|
2523 #endif |
|
2524 #if defined(__Userspace__) |
|
2525 struct sockaddr_conn sconn; |
|
2526 #endif |
|
2527 |
|
2528 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
2529 "sctp_handle_cookie: handling COOKIE-ECHO\n"); |
|
2530 |
|
2531 if (inp_p == NULL) { |
|
2532 return (NULL); |
|
2533 } |
|
2534 cookie = &cp->cookie; |
|
2535 cookie_offset = offset + sizeof(struct sctp_chunkhdr); |
|
2536 cookie_len = ntohs(cp->ch.chunk_length); |
|
2537 |
|
2538 if ((cookie->peerport != sh->src_port) && |
|
2539 (cookie->myport != sh->dest_port) && |
|
2540 (cookie->my_vtag != sh->v_tag)) { |
|
2541 /* |
|
2542 * invalid ports or bad tag. Note that we always leave the |
|
2543 * v_tag in the header in network order and when we stored |
|
2544 * it in the my_vtag slot we also left it in network order. |
|
2545 * This maintains the match even though it may be in the |
|
2546 * opposite byte order of the machine :-> |
|
2547 */ |
|
2548 return (NULL); |
|
2549 } |
|
2550 if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) + |
|
2551 sizeof(struct sctp_init_chunk) + |
|
2552 sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) { |
|
2553 /* cookie too small */ |
|
2554 return (NULL); |
|
2555 } |
|
2556 /* |
|
2557 * split off the signature into its own mbuf (since it should not be |
|
2558 * calculated in the sctp_hmac_m() call). |
|
2559 */ |
|
2560 sig_offset = offset + cookie_len - SCTP_SIGNATURE_SIZE; |
|
2561 m_sig = m_split(m, sig_offset, M_NOWAIT); |
|
2562 if (m_sig == NULL) { |
|
2563 /* out of memory or ?? */ |
|
2564 return (NULL); |
|
2565 } |
|
2566 #ifdef SCTP_MBUF_LOGGING |
|
2567 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
|
2568 struct mbuf *mat; |
|
2569 |
|
2570 for (mat = m_sig; mat; mat = SCTP_BUF_NEXT(mat)) { |
|
2571 if (SCTP_BUF_IS_EXTENDED(mat)) { |
|
2572 sctp_log_mb(mat, SCTP_MBUF_SPLIT); |
|
2573 } |
|
2574 } |
|
2575 } |
|
2576 #endif |
|
2577 |
|
2578 /* |
|
2579 * compute the signature/digest for the cookie |
|
2580 */ |
|
2581 ep = &(*inp_p)->sctp_ep; |
|
2582 l_inp = *inp_p; |
|
2583 if (l_stcb) { |
|
2584 SCTP_TCB_UNLOCK(l_stcb); |
|
2585 } |
|
2586 SCTP_INP_RLOCK(l_inp); |
|
2587 if (l_stcb) { |
|
2588 SCTP_TCB_LOCK(l_stcb); |
|
2589 } |
|
2590 /* which cookie is it? */ |
|
2591 if ((cookie->time_entered.tv_sec < (long)ep->time_of_secret_change) && |
|
2592 (ep->current_secret_number != ep->last_secret_number)) { |
|
2593 /* it's the old cookie */ |
|
2594 (void)sctp_hmac_m(SCTP_HMAC, |
|
2595 (uint8_t *)ep->secret_key[(int)ep->last_secret_number], |
|
2596 SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); |
|
2597 } else { |
|
2598 /* it's the current cookie */ |
|
2599 (void)sctp_hmac_m(SCTP_HMAC, |
|
2600 (uint8_t *)ep->secret_key[(int)ep->current_secret_number], |
|
2601 SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); |
|
2602 } |
|
2603 /* get the signature */ |
|
2604 SCTP_INP_RUNLOCK(l_inp); |
|
2605 sig = (uint8_t *) sctp_m_getptr(m_sig, 0, SCTP_SIGNATURE_SIZE, (uint8_t *) & tmp_sig); |
|
2606 if (sig == NULL) { |
|
2607 /* couldn't find signature */ |
|
2608 sctp_m_freem(m_sig); |
|
2609 return (NULL); |
|
2610 } |
|
2611 /* compare the received digest with the computed digest */ |
|
2612 if (memcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) != 0) { |
|
2613 /* try the old cookie? */ |
|
2614 if ((cookie->time_entered.tv_sec == (long)ep->time_of_secret_change) && |
|
2615 (ep->current_secret_number != ep->last_secret_number)) { |
|
2616 /* compute digest with old */ |
|
2617 (void)sctp_hmac_m(SCTP_HMAC, |
|
2618 (uint8_t *)ep->secret_key[(int)ep->last_secret_number], |
|
2619 SCTP_SECRET_SIZE, m, cookie_offset, calc_sig, 0); |
|
2620 /* compare */ |
|
2621 if (memcmp(calc_sig, sig, SCTP_SIGNATURE_SIZE) == 0) |
|
2622 cookie_ok = 1; |
|
2623 } |
|
2624 } else { |
|
2625 cookie_ok = 1; |
|
2626 } |
|
2627 |
|
2628 /* |
|
2629 * Now before we continue we must reconstruct our mbuf so that |
|
2630 * normal processing of any other chunks will work. |
|
2631 */ |
|
2632 { |
|
2633 struct mbuf *m_at; |
|
2634 |
|
2635 m_at = m; |
|
2636 while (SCTP_BUF_NEXT(m_at) != NULL) { |
|
2637 m_at = SCTP_BUF_NEXT(m_at); |
|
2638 } |
|
2639 SCTP_BUF_NEXT(m_at) = m_sig; |
|
2640 } |
|
2641 |
|
2642 if (cookie_ok == 0) { |
|
2643 SCTPDBG(SCTP_DEBUG_INPUT2, "handle_cookie_echo: cookie signature validation failed!\n"); |
|
2644 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
2645 "offset = %u, cookie_offset = %u, sig_offset = %u\n", |
|
2646 (uint32_t) offset, cookie_offset, sig_offset); |
|
2647 return (NULL); |
|
2648 } |
|
2649 |
|
2650 /* |
|
2651 * check the cookie timestamps to be sure it's not stale |
|
2652 */ |
|
2653 (void)SCTP_GETTIME_TIMEVAL(&now); |
|
2654 /* Expire time is in Ticks, so we convert to seconds */ |
|
2655 time_expires.tv_sec = cookie->time_entered.tv_sec + TICKS_TO_SEC(cookie->cookie_life); |
|
2656 time_expires.tv_usec = cookie->time_entered.tv_usec; |
|
2657 /* TODO sctp_constants.h needs alternative time macros when |
|
2658 * _KERNEL is undefined. |
|
2659 */ |
|
2660 #ifndef __FreeBSD__ |
|
2661 if (timercmp(&now, &time_expires, >)) |
|
2662 #else |
|
2663 if (timevalcmp(&now, &time_expires, >)) |
|
2664 #endif |
|
2665 { |
|
2666 /* cookie is stale! */ |
|
2667 struct mbuf *op_err; |
|
2668 struct sctp_stale_cookie_msg *scm; |
|
2669 uint32_t tim; |
|
2670 op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_stale_cookie_msg), |
|
2671 0, M_NOWAIT, 1, MT_DATA); |
|
2672 if (op_err == NULL) { |
|
2673 /* FOOBAR */ |
|
2674 return (NULL); |
|
2675 } |
|
2676 /* Set the len */ |
|
2677 SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg); |
|
2678 scm = mtod(op_err, struct sctp_stale_cookie_msg *); |
|
2679 scm->ph.param_type = htons(SCTP_CAUSE_STALE_COOKIE); |
|
2680 scm->ph.param_length = htons((sizeof(struct sctp_paramhdr) + |
|
2681 (sizeof(uint32_t)))); |
|
2682 /* seconds to usec */ |
|
2683 tim = (now.tv_sec - time_expires.tv_sec) * 1000000; |
|
2684 /* add in usec */ |
|
2685 if (tim == 0) |
|
2686 tim = now.tv_usec - cookie->time_entered.tv_usec; |
|
2687 scm->time_usec = htonl(tim); |
|
2688 sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err, |
|
2689 #if defined(__FreeBSD__) |
|
2690 use_mflowid, mflowid, |
|
2691 #endif |
|
2692 vrf_id, port); |
|
2693 return (NULL); |
|
2694 } |
|
2695 /* |
|
2696 * Now we must see with the lookup address if we have an existing |
|
2697 * asoc. This will only happen if we were in the COOKIE-WAIT state |
|
2698 * and a INIT collided with us and somewhere the peer sent the |
|
2699 * cookie on another address besides the single address our assoc |
|
2700 * had for him. In this case we will have one of the tie-tags set at |
|
2701 * least AND the address field in the cookie can be used to look it |
|
2702 * up. |
|
2703 */ |
|
2704 to = NULL; |
|
2705 switch (cookie->addr_type) { |
|
2706 #ifdef INET6 |
|
2707 case SCTP_IPV6_ADDRESS: |
|
2708 memset(&sin6, 0, sizeof(sin6)); |
|
2709 sin6.sin6_family = AF_INET6; |
|
2710 #ifdef HAVE_SIN6_LEN |
|
2711 sin6.sin6_len = sizeof(sin6); |
|
2712 #endif |
|
2713 sin6.sin6_port = sh->src_port; |
|
2714 sin6.sin6_scope_id = cookie->scope_id; |
|
2715 memcpy(&sin6.sin6_addr.s6_addr, cookie->address, |
|
2716 sizeof(sin6.sin6_addr.s6_addr)); |
|
2717 to = (struct sockaddr *)&sin6; |
|
2718 break; |
|
2719 #endif |
|
2720 #ifdef INET |
|
2721 case SCTP_IPV4_ADDRESS: |
|
2722 memset(&sin, 0, sizeof(sin)); |
|
2723 sin.sin_family = AF_INET; |
|
2724 #ifdef HAVE_SIN_LEN |
|
2725 sin.sin_len = sizeof(sin); |
|
2726 #endif |
|
2727 sin.sin_port = sh->src_port; |
|
2728 sin.sin_addr.s_addr = cookie->address[0]; |
|
2729 to = (struct sockaddr *)&sin; |
|
2730 break; |
|
2731 #endif |
|
2732 #if defined(__Userspace__) |
|
2733 case SCTP_CONN_ADDRESS: |
|
2734 memset(&sconn, 0, sizeof(struct sockaddr_conn)); |
|
2735 sconn.sconn_family = AF_CONN; |
|
2736 #ifdef HAVE_SCONN_LEN |
|
2737 sconn.sconn_len = sizeof(struct sockaddr_conn); |
|
2738 #endif |
|
2739 sconn.sconn_port = sh->src_port; |
|
2740 memcpy(&sconn.sconn_addr, cookie->address, sizeof(void *)); |
|
2741 to = (struct sockaddr *)&sconn; |
|
2742 break; |
|
2743 #endif |
|
2744 default: |
|
2745 /* This should not happen */ |
|
2746 return (NULL); |
|
2747 } |
|
2748 if ((*stcb == NULL) && to) { |
|
2749 /* Yep, lets check */ |
|
2750 *stcb = sctp_findassociation_ep_addr(inp_p, to, netp, dst, NULL); |
|
2751 if (*stcb == NULL) { |
|
2752 /* |
|
2753 * We should have only got back the same inp. If we |
|
2754 * got back a different ep we have a problem. The |
|
2755 * original findep got back l_inp and now |
|
2756 */ |
|
2757 if (l_inp != *inp_p) { |
|
2758 SCTP_PRINTF("Bad problem find_ep got a diff inp then special_locate?\n"); |
|
2759 } |
|
2760 } else { |
|
2761 if (*locked_tcb == NULL) { |
|
2762 /* In this case we found the assoc only |
|
2763 * after we locked the create lock. This means |
|
2764 * we are in a colliding case and we must make |
|
2765 * sure that we unlock the tcb if its one of the |
|
2766 * cases where we throw away the incoming packets. |
|
2767 */ |
|
2768 *locked_tcb = *stcb; |
|
2769 |
|
2770 /* We must also increment the inp ref count |
|
2771 * since the ref_count flags was set when we |
|
2772 * did not find the TCB, now we found it which |
|
2773 * reduces the refcount.. we must raise it back |
|
2774 * out to balance it all :-) |
|
2775 */ |
|
2776 SCTP_INP_INCR_REF((*stcb)->sctp_ep); |
|
2777 if ((*stcb)->sctp_ep != l_inp) { |
|
2778 SCTP_PRINTF("Huh? ep:%p diff then l_inp:%p?\n", |
|
2779 (void *)(*stcb)->sctp_ep, (void *)l_inp); |
|
2780 } |
|
2781 } |
|
2782 } |
|
2783 } |
|
2784 if (to == NULL) { |
|
2785 return (NULL); |
|
2786 } |
|
2787 |
|
2788 cookie_len -= SCTP_SIGNATURE_SIZE; |
|
2789 if (*stcb == NULL) { |
|
2790 /* this is the "normal" case... get a new TCB */ |
|
2791 *stcb = sctp_process_cookie_new(m, iphlen, offset, src, dst, sh, |
|
2792 cookie, cookie_len, *inp_p, |
|
2793 netp, to, ¬ification, |
|
2794 auth_skipped, auth_offset, auth_len, |
|
2795 #if defined(__FreeBSD__) |
|
2796 use_mflowid, mflowid, |
|
2797 #endif |
|
2798 vrf_id, port); |
|
2799 } else { |
|
2800 /* this is abnormal... cookie-echo on existing TCB */ |
|
2801 had_a_existing_tcb = 1; |
|
2802 *stcb = sctp_process_cookie_existing(m, iphlen, offset, |
|
2803 src, dst, sh, |
|
2804 cookie, cookie_len, *inp_p, *stcb, netp, to, |
|
2805 ¬ification, auth_skipped, auth_offset, auth_len, |
|
2806 #if defined(__FreeBSD__) |
|
2807 use_mflowid, mflowid, |
|
2808 #endif |
|
2809 vrf_id, port); |
|
2810 } |
|
2811 |
|
2812 if (*stcb == NULL) { |
|
2813 /* still no TCB... must be bad cookie-echo */ |
|
2814 return (NULL); |
|
2815 } |
|
2816 #if defined(__FreeBSD__) |
|
2817 if ((*netp != NULL) && (use_mflowid != 0)) { |
|
2818 (*netp)->flowid = mflowid; |
|
2819 #ifdef INVARIANTS |
|
2820 (*netp)->flowidset = 1; |
|
2821 #endif |
|
2822 } |
|
2823 #endif |
|
2824 /* |
|
2825 * Ok, we built an association so confirm the address we sent the |
|
2826 * INIT-ACK to. |
|
2827 */ |
|
2828 netl = sctp_findnet(*stcb, to); |
|
2829 /* |
|
2830 * This code should in theory NOT run but |
|
2831 */ |
|
2832 if (netl == NULL) { |
|
2833 /* TSNH! Huh, why do I need to add this address here? */ |
|
2834 if (sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) { |
|
2835 return (NULL); |
|
2836 } |
|
2837 netl = sctp_findnet(*stcb, to); |
|
2838 } |
|
2839 if (netl) { |
|
2840 if (netl->dest_state & SCTP_ADDR_UNCONFIRMED) { |
|
2841 netl->dest_state &= ~SCTP_ADDR_UNCONFIRMED; |
|
2842 (void)sctp_set_primary_addr((*stcb), (struct sockaddr *)NULL, |
|
2843 netl); |
|
2844 send_int_conf = 1; |
|
2845 } |
|
2846 } |
|
2847 sctp_start_net_timers(*stcb); |
|
2848 if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { |
|
2849 if (!had_a_existing_tcb || |
|
2850 (((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { |
|
2851 /* |
|
2852 * If we have a NEW cookie or the connect never |
|
2853 * reached the connected state during collision we |
|
2854 * must do the TCP accept thing. |
|
2855 */ |
|
2856 struct socket *so, *oso; |
|
2857 struct sctp_inpcb *inp; |
|
2858 |
|
2859 if (notification == SCTP_NOTIFY_ASSOC_RESTART) { |
|
2860 /* |
|
2861 * For a restart we will keep the same |
|
2862 * socket, no need to do anything. I THINK!! |
|
2863 */ |
|
2864 sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
2865 if (send_int_conf) { |
|
2866 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, |
|
2867 (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); |
|
2868 } |
|
2869 return (m); |
|
2870 } |
|
2871 oso = (*inp_p)->sctp_socket; |
|
2872 #if (defined(__FreeBSD__) && __FreeBSD_version < 700000) |
|
2873 /* |
|
2874 * We do this to keep the sockets side happy during |
|
2875 * the sonewcon ONLY. |
|
2876 */ |
|
2877 NET_LOCK_GIANT(); |
|
2878 #endif |
|
2879 atomic_add_int(&(*stcb)->asoc.refcnt, 1); |
|
2880 SCTP_TCB_UNLOCK((*stcb)); |
|
2881 #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 |
|
2882 CURVNET_SET(oso->so_vnet); |
|
2883 #endif |
|
2884 #if defined(__APPLE__) |
|
2885 SCTP_SOCKET_LOCK(oso, 1); |
|
2886 #endif |
|
2887 so = sonewconn(oso, 0 |
|
2888 #if defined(__APPLE__) |
|
2889 ,NULL |
|
2890 #endif |
|
2891 #ifdef __Panda__ |
|
2892 ,NULL , (*inp_p)->def_vrf_id |
|
2893 #endif |
|
2894 ); |
|
2895 #if (defined(__FreeBSD__) && __FreeBSD_version < 700000) |
|
2896 NET_UNLOCK_GIANT(); |
|
2897 #endif |
|
2898 #if defined(__APPLE__) |
|
2899 SCTP_SOCKET_UNLOCK(oso, 1); |
|
2900 #endif |
|
2901 #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 |
|
2902 CURVNET_RESTORE(); |
|
2903 #endif |
|
2904 SCTP_TCB_LOCK((*stcb)); |
|
2905 atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); |
|
2906 |
|
2907 if (so == NULL) { |
|
2908 struct mbuf *op_err; |
|
2909 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2910 struct socket *pcb_so; |
|
2911 #endif |
|
2912 /* Too many sockets */ |
|
2913 SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: no room for another socket!\n"); |
|
2914 op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); |
|
2915 sctp_abort_association(*inp_p, NULL, m, iphlen, |
|
2916 src, dst, sh, op_err, |
|
2917 #if defined(__FreeBSD__) |
|
2918 use_mflowid, mflowid, |
|
2919 #endif |
|
2920 vrf_id, port); |
|
2921 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2922 pcb_so = SCTP_INP_SO(*inp_p); |
|
2923 atomic_add_int(&(*stcb)->asoc.refcnt, 1); |
|
2924 SCTP_TCB_UNLOCK((*stcb)); |
|
2925 SCTP_SOCKET_LOCK(pcb_so, 1); |
|
2926 SCTP_TCB_LOCK((*stcb)); |
|
2927 atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); |
|
2928 #endif |
|
2929 (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_20); |
|
2930 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
2931 SCTP_SOCKET_UNLOCK(pcb_so, 1); |
|
2932 #endif |
|
2933 return (NULL); |
|
2934 } |
|
2935 inp = (struct sctp_inpcb *)so->so_pcb; |
|
2936 SCTP_INP_INCR_REF(inp); |
|
2937 /* |
|
2938 * We add the unbound flag here so that |
|
2939 * if we get an soabort() before we get the |
|
2940 * move_pcb done, we will properly cleanup. |
|
2941 */ |
|
2942 inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE | |
|
2943 SCTP_PCB_FLAGS_CONNECTED | |
|
2944 SCTP_PCB_FLAGS_IN_TCPPOOL | |
|
2945 SCTP_PCB_FLAGS_UNBOUND | |
|
2946 (SCTP_PCB_COPY_FLAGS & (*inp_p)->sctp_flags) | |
|
2947 SCTP_PCB_FLAGS_DONT_WAKE); |
|
2948 inp->sctp_features = (*inp_p)->sctp_features; |
|
2949 inp->sctp_mobility_features = (*inp_p)->sctp_mobility_features; |
|
2950 inp->sctp_socket = so; |
|
2951 inp->sctp_frag_point = (*inp_p)->sctp_frag_point; |
|
2952 inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off; |
|
2953 inp->sctp_ecn_enable = (*inp_p)->sctp_ecn_enable; |
|
2954 inp->partial_delivery_point = (*inp_p)->partial_delivery_point; |
|
2955 inp->sctp_context = (*inp_p)->sctp_context; |
|
2956 inp->local_strreset_support = (*inp_p)->local_strreset_support; |
|
2957 inp->inp_starting_point_for_iterator = NULL; |
|
2958 #if defined(__Userspace__) |
|
2959 inp->ulp_info = (*inp_p)->ulp_info; |
|
2960 inp->recv_callback = (*inp_p)->recv_callback; |
|
2961 inp->send_callback = (*inp_p)->send_callback; |
|
2962 inp->send_sb_threshold = (*inp_p)->send_sb_threshold; |
|
2963 #endif |
|
2964 /* |
|
2965 * copy in the authentication parameters from the |
|
2966 * original endpoint |
|
2967 */ |
|
2968 if (inp->sctp_ep.local_hmacs) |
|
2969 sctp_free_hmaclist(inp->sctp_ep.local_hmacs); |
|
2970 inp->sctp_ep.local_hmacs = |
|
2971 sctp_copy_hmaclist((*inp_p)->sctp_ep.local_hmacs); |
|
2972 if (inp->sctp_ep.local_auth_chunks) |
|
2973 sctp_free_chunklist(inp->sctp_ep.local_auth_chunks); |
|
2974 inp->sctp_ep.local_auth_chunks = |
|
2975 sctp_copy_chunklist((*inp_p)->sctp_ep.local_auth_chunks); |
|
2976 |
|
2977 /* |
|
2978 * Now we must move it from one hash table to |
|
2979 * another and get the tcb in the right place. |
|
2980 */ |
|
2981 |
|
2982 /* This is where the one-2-one socket is put into |
|
2983 * the accept state waiting for the accept! |
|
2984 */ |
|
2985 if (*stcb) { |
|
2986 (*stcb)->asoc.state |= SCTP_STATE_IN_ACCEPT_QUEUE; |
|
2987 } |
|
2988 sctp_move_pcb_and_assoc(*inp_p, inp, *stcb); |
|
2989 |
|
2990 atomic_add_int(&(*stcb)->asoc.refcnt, 1); |
|
2991 SCTP_TCB_UNLOCK((*stcb)); |
|
2992 |
|
2993 #if defined(__FreeBSD__) |
|
2994 sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, |
|
2995 0); |
|
2996 #else |
|
2997 sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT); |
|
2998 #endif |
|
2999 SCTP_TCB_LOCK((*stcb)); |
|
3000 atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); |
|
3001 |
|
3002 |
|
3003 /* now we must check to see if we were aborted while |
|
3004 * the move was going on and the lock/unlock happened. |
|
3005 */ |
|
3006 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { |
|
3007 /* yep it was, we leave the |
|
3008 * assoc attached to the socket since |
|
3009 * the sctp_inpcb_free() call will send |
|
3010 * an abort for us. |
|
3011 */ |
|
3012 SCTP_INP_DECR_REF(inp); |
|
3013 return (NULL); |
|
3014 } |
|
3015 SCTP_INP_DECR_REF(inp); |
|
3016 /* Switch over to the new guy */ |
|
3017 *inp_p = inp; |
|
3018 sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
3019 if (send_int_conf) { |
|
3020 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, |
|
3021 (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); |
|
3022 } |
|
3023 |
|
3024 /* Pull it from the incomplete queue and wake the guy */ |
|
3025 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3026 atomic_add_int(&(*stcb)->asoc.refcnt, 1); |
|
3027 SCTP_TCB_UNLOCK((*stcb)); |
|
3028 SCTP_SOCKET_LOCK(so, 1); |
|
3029 #endif |
|
3030 soisconnected(so); |
|
3031 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3032 SCTP_TCB_LOCK((*stcb)); |
|
3033 atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); |
|
3034 SCTP_SOCKET_UNLOCK(so, 1); |
|
3035 #endif |
|
3036 return (m); |
|
3037 } |
|
3038 } |
|
3039 if (notification) { |
|
3040 sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
3041 } |
|
3042 if (send_int_conf) { |
|
3043 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, |
|
3044 (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED); |
|
3045 } |
|
3046 return (m); |
|
3047 } |
|
3048 |
|
3049 static void |
|
3050 sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, |
|
3051 struct sctp_tcb *stcb, struct sctp_nets *net) |
|
3052 { |
|
3053 /* cp must not be used, others call this without a c-ack :-) */ |
|
3054 struct sctp_association *asoc; |
|
3055 |
|
3056 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
3057 "sctp_handle_cookie_ack: handling COOKIE-ACK\n"); |
|
3058 if (stcb == NULL) |
|
3059 return; |
|
3060 |
|
3061 asoc = &stcb->asoc; |
|
3062 |
|
3063 sctp_stop_all_cookie_timers(stcb); |
|
3064 /* process according to association state */ |
|
3065 if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) { |
|
3066 /* state change only needed when I am in right state */ |
|
3067 SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); |
|
3068 SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); |
|
3069 sctp_start_net_timers(stcb); |
|
3070 if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { |
|
3071 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
3072 stcb->sctp_ep, stcb, asoc->primary_destination); |
|
3073 |
|
3074 } |
|
3075 /* update RTO */ |
|
3076 SCTP_STAT_INCR_COUNTER32(sctps_activeestab); |
|
3077 SCTP_STAT_INCR_GAUGE32(sctps_currestab); |
|
3078 if (asoc->overall_error_count == 0) { |
|
3079 net->RTO = sctp_calculate_rto(stcb, asoc, net, |
|
3080 &asoc->time_entered, sctp_align_safe_nocopy, |
|
3081 SCTP_RTT_FROM_NON_DATA); |
|
3082 } |
|
3083 (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); |
|
3084 sctp_ulp_notify(SCTP_NOTIFY_ASSOC_UP, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
3085 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3086 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
3087 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3088 struct socket *so; |
|
3089 |
|
3090 #endif |
|
3091 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
3092 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3093 so = SCTP_INP_SO(stcb->sctp_ep); |
|
3094 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
3095 SCTP_TCB_UNLOCK(stcb); |
|
3096 SCTP_SOCKET_LOCK(so, 1); |
|
3097 SCTP_TCB_LOCK(stcb); |
|
3098 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
3099 #endif |
|
3100 if ((stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) == 0) { |
|
3101 soisconnected(stcb->sctp_socket); |
|
3102 } |
|
3103 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3104 SCTP_SOCKET_UNLOCK(so, 1); |
|
3105 #endif |
|
3106 } |
|
3107 /* |
|
3108 * since we did not send a HB make sure we don't double |
|
3109 * things |
|
3110 */ |
|
3111 net->hb_responded = 1; |
|
3112 |
|
3113 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { |
|
3114 /* We don't need to do the asconf thing, |
|
3115 * nor hb or autoclose if the socket is closed. |
|
3116 */ |
|
3117 goto closed_socket; |
|
3118 } |
|
3119 |
|
3120 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, |
|
3121 stcb, net); |
|
3122 |
|
3123 |
|
3124 if (stcb->asoc.sctp_autoclose_ticks && |
|
3125 sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_AUTOCLOSE)) { |
|
3126 sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, |
|
3127 stcb->sctp_ep, stcb, NULL); |
|
3128 } |
|
3129 /* |
|
3130 * send ASCONF if parameters are pending and ASCONFs are |
|
3131 * allowed (eg. addresses changed when init/cookie echo were |
|
3132 * in flight) |
|
3133 */ |
|
3134 if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DO_ASCONF)) && |
|
3135 (stcb->asoc.peer_supports_asconf) && |
|
3136 (!TAILQ_EMPTY(&stcb->asoc.asconf_queue))) { |
|
3137 #ifdef SCTP_TIMER_BASED_ASCONF |
|
3138 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, |
|
3139 stcb->sctp_ep, stcb, |
|
3140 stcb->asoc.primary_destination); |
|
3141 #else |
|
3142 sctp_send_asconf(stcb, stcb->asoc.primary_destination, |
|
3143 SCTP_ADDR_NOT_LOCKED); |
|
3144 #endif |
|
3145 } |
|
3146 } |
|
3147 closed_socket: |
|
3148 /* Toss the cookie if I can */ |
|
3149 sctp_toss_old_cookies(stcb, asoc); |
|
3150 if (!TAILQ_EMPTY(&asoc->sent_queue)) { |
|
3151 /* Restart the timer if we have pending data */ |
|
3152 struct sctp_tmit_chunk *chk; |
|
3153 |
|
3154 chk = TAILQ_FIRST(&asoc->sent_queue); |
|
3155 sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); |
|
3156 } |
|
3157 } |
|
3158 |
|
3159 static void |
|
3160 sctp_handle_ecn_echo(struct sctp_ecne_chunk *cp, |
|
3161 struct sctp_tcb *stcb) |
|
3162 { |
|
3163 struct sctp_nets *net; |
|
3164 struct sctp_tmit_chunk *lchk; |
|
3165 struct sctp_ecne_chunk bkup; |
|
3166 uint8_t override_bit; |
|
3167 uint32_t tsn, window_data_tsn; |
|
3168 int len; |
|
3169 unsigned int pkt_cnt; |
|
3170 |
|
3171 len = ntohs(cp->ch.chunk_length); |
|
3172 if ((len != sizeof(struct sctp_ecne_chunk)) && |
|
3173 (len != sizeof(struct old_sctp_ecne_chunk))) { |
|
3174 return; |
|
3175 } |
|
3176 if (len == sizeof(struct old_sctp_ecne_chunk)) { |
|
3177 /* Its the old format */ |
|
3178 memcpy(&bkup, cp, sizeof(struct old_sctp_ecne_chunk)); |
|
3179 bkup.num_pkts_since_cwr = htonl(1); |
|
3180 cp = &bkup; |
|
3181 } |
|
3182 SCTP_STAT_INCR(sctps_recvecne); |
|
3183 tsn = ntohl(cp->tsn); |
|
3184 pkt_cnt = ntohl(cp->num_pkts_since_cwr); |
|
3185 lchk = TAILQ_LAST(&stcb->asoc.send_queue, sctpchunk_listhead); |
|
3186 if (lchk == NULL) { |
|
3187 window_data_tsn = stcb->asoc.sending_seq - 1; |
|
3188 } else { |
|
3189 window_data_tsn = lchk->rec.data.TSN_seq; |
|
3190 } |
|
3191 |
|
3192 /* Find where it was sent to if possible. */ |
|
3193 net = NULL; |
|
3194 TAILQ_FOREACH(lchk, &stcb->asoc.sent_queue, sctp_next) { |
|
3195 if (lchk->rec.data.TSN_seq == tsn) { |
|
3196 net = lchk->whoTo; |
|
3197 net->ecn_prev_cwnd = lchk->rec.data.cwnd_at_send; |
|
3198 break; |
|
3199 } |
|
3200 if (SCTP_TSN_GT(lchk->rec.data.TSN_seq, tsn)) { |
|
3201 break; |
|
3202 } |
|
3203 } |
|
3204 if (net == NULL) { |
|
3205 /* |
|
3206 * What to do. A previous send of a |
|
3207 * CWR was possibly lost. See how old it is, we |
|
3208 * may have it marked on the actual net. |
|
3209 */ |
|
3210 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
3211 if (tsn == net->last_cwr_tsn) { |
|
3212 /* Found him, send it off */ |
|
3213 break; |
|
3214 } |
|
3215 } |
|
3216 if (net == NULL) { |
|
3217 /* |
|
3218 * If we reach here, we need to send a special |
|
3219 * CWR that says hey, we did this a long time |
|
3220 * ago and you lost the response. |
|
3221 */ |
|
3222 net = TAILQ_FIRST(&stcb->asoc.nets); |
|
3223 if (net == NULL) { |
|
3224 /* TSNH */ |
|
3225 return; |
|
3226 } |
|
3227 override_bit = SCTP_CWR_REDUCE_OVERRIDE; |
|
3228 } else { |
|
3229 override_bit = 0; |
|
3230 } |
|
3231 } else { |
|
3232 override_bit = 0; |
|
3233 } |
|
3234 if (SCTP_TSN_GT(tsn, net->cwr_window_tsn) && |
|
3235 ((override_bit&SCTP_CWR_REDUCE_OVERRIDE) == 0)) { |
|
3236 /* JRS - Use the congestion control given in the pluggable CC module */ |
|
3237 stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo(stcb, net, 0, pkt_cnt); |
|
3238 /* |
|
3239 * We reduce once every RTT. So we will only lower cwnd at |
|
3240 * the next sending seq i.e. the window_data_tsn |
|
3241 */ |
|
3242 net->cwr_window_tsn = window_data_tsn; |
|
3243 net->ecn_ce_pkt_cnt += pkt_cnt; |
|
3244 net->lost_cnt = pkt_cnt; |
|
3245 net->last_cwr_tsn = tsn; |
|
3246 } else { |
|
3247 override_bit |= SCTP_CWR_IN_SAME_WINDOW; |
|
3248 if (SCTP_TSN_GT(tsn, net->last_cwr_tsn) && |
|
3249 ((override_bit&SCTP_CWR_REDUCE_OVERRIDE) == 0)) { |
|
3250 /* |
|
3251 * Another loss in the same window update how |
|
3252 * many marks/packets lost we have had. |
|
3253 */ |
|
3254 int cnt = 1; |
|
3255 if (pkt_cnt > net->lost_cnt) { |
|
3256 /* Should be the case */ |
|
3257 cnt = (pkt_cnt - net->lost_cnt); |
|
3258 net->ecn_ce_pkt_cnt += cnt; |
|
3259 } |
|
3260 net->lost_cnt = pkt_cnt; |
|
3261 net->last_cwr_tsn = tsn; |
|
3262 /* |
|
3263 * Most CC functions will ignore this call, since we are in-window |
|
3264 * yet of the initial CE the peer saw. |
|
3265 */ |
|
3266 stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo(stcb, net, 1, cnt); |
|
3267 } |
|
3268 } |
|
3269 /* |
|
3270 * We always send a CWR this way if our previous one was lost our |
|
3271 * peer will get an update, or if it is not time again to reduce we |
|
3272 * still get the cwr to the peer. Note we set the override when we |
|
3273 * could not find the TSN on the chunk or the destination network. |
|
3274 */ |
|
3275 sctp_send_cwr(stcb, net, net->last_cwr_tsn, override_bit); |
|
3276 } |
|
3277 |
|
3278 static void |
|
3279 sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sctp_nets *net) |
|
3280 { |
|
3281 /* |
|
3282 * Here we get a CWR from the peer. We must look in the outqueue and |
|
3283 * make sure that we have a covered ECNE in the control chunk part. |
|
3284 * If so remove it. |
|
3285 */ |
|
3286 struct sctp_tmit_chunk *chk; |
|
3287 struct sctp_ecne_chunk *ecne; |
|
3288 int override; |
|
3289 uint32_t cwr_tsn; |
|
3290 cwr_tsn = ntohl(cp->tsn); |
|
3291 |
|
3292 override = cp->ch.chunk_flags & SCTP_CWR_REDUCE_OVERRIDE; |
|
3293 TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { |
|
3294 if (chk->rec.chunk_id.id != SCTP_ECN_ECHO) { |
|
3295 continue; |
|
3296 } |
|
3297 if ((override == 0) && (chk->whoTo != net)) { |
|
3298 /* Must be from the right src unless override is set */ |
|
3299 continue; |
|
3300 } |
|
3301 ecne = mtod(chk->data, struct sctp_ecne_chunk *); |
|
3302 if (SCTP_TSN_GE(cwr_tsn, ntohl(ecne->tsn))) { |
|
3303 /* this covers this ECNE, we can remove it */ |
|
3304 stcb->asoc.ecn_echo_cnt_onq--; |
|
3305 TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, |
|
3306 sctp_next); |
|
3307 if (chk->data) { |
|
3308 sctp_m_freem(chk->data); |
|
3309 chk->data = NULL; |
|
3310 } |
|
3311 stcb->asoc.ctrl_queue_cnt--; |
|
3312 sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
|
3313 if (override == 0) { |
|
3314 break; |
|
3315 } |
|
3316 } |
|
3317 } |
|
3318 } |
|
3319 |
|
3320 static void |
|
3321 sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSED, |
|
3322 struct sctp_tcb *stcb, struct sctp_nets *net) |
|
3323 { |
|
3324 struct sctp_association *asoc; |
|
3325 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3326 struct socket *so; |
|
3327 #endif |
|
3328 |
|
3329 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
3330 "sctp_handle_shutdown_complete: handling SHUTDOWN-COMPLETE\n"); |
|
3331 if (stcb == NULL) |
|
3332 return; |
|
3333 |
|
3334 asoc = &stcb->asoc; |
|
3335 /* process according to association state */ |
|
3336 if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) { |
|
3337 /* unexpected SHUTDOWN-COMPLETE... so ignore... */ |
|
3338 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
3339 "sctp_handle_shutdown_complete: not in SCTP_STATE_SHUTDOWN_ACK_SENT --- ignore\n"); |
|
3340 SCTP_TCB_UNLOCK(stcb); |
|
3341 return; |
|
3342 } |
|
3343 /* notify upper layer protocol */ |
|
3344 if (stcb->sctp_socket) { |
|
3345 sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
3346 } |
|
3347 #ifdef INVARIANTS |
|
3348 if (!TAILQ_EMPTY(&asoc->send_queue) || |
|
3349 !TAILQ_EMPTY(&asoc->sent_queue) || |
|
3350 !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { |
|
3351 panic("Queues are not empty when handling SHUTDOWN-COMPLETE"); |
|
3352 } |
|
3353 #endif |
|
3354 /* stop the timer */ |
|
3355 sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_22); |
|
3356 SCTP_STAT_INCR_COUNTER32(sctps_shutdown); |
|
3357 /* free the TCB */ |
|
3358 SCTPDBG(SCTP_DEBUG_INPUT2, |
|
3359 "sctp_handle_shutdown_complete: calls free-asoc\n"); |
|
3360 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3361 so = SCTP_INP_SO(stcb->sctp_ep); |
|
3362 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
3363 SCTP_TCB_UNLOCK(stcb); |
|
3364 SCTP_SOCKET_LOCK(so, 1); |
|
3365 SCTP_TCB_LOCK(stcb); |
|
3366 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
3367 #endif |
|
3368 (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_23); |
|
3369 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
3370 SCTP_SOCKET_UNLOCK(so, 1); |
|
3371 #endif |
|
3372 return; |
|
3373 } |
|
3374 |
|
3375 static int |
|
3376 process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, |
|
3377 struct sctp_nets *net, uint8_t flg) |
|
3378 { |
|
3379 switch (desc->chunk_type) { |
|
3380 case SCTP_DATA: |
|
3381 /* find the tsn to resend (possibly */ |
|
3382 { |
|
3383 uint32_t tsn; |
|
3384 struct sctp_tmit_chunk *tp1; |
|
3385 |
|
3386 tsn = ntohl(desc->tsn_ifany); |
|
3387 TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { |
|
3388 if (tp1->rec.data.TSN_seq == tsn) { |
|
3389 /* found it */ |
|
3390 break; |
|
3391 } |
|
3392 if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, tsn)) { |
|
3393 /* not found */ |
|
3394 tp1 = NULL; |
|
3395 break; |
|
3396 } |
|
3397 } |
|
3398 if (tp1 == NULL) { |
|
3399 /* |
|
3400 * Do it the other way , aka without paying |
|
3401 * attention to queue seq order. |
|
3402 */ |
|
3403 SCTP_STAT_INCR(sctps_pdrpdnfnd); |
|
3404 TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { |
|
3405 if (tp1->rec.data.TSN_seq == tsn) { |
|
3406 /* found it */ |
|
3407 break; |
|
3408 } |
|
3409 } |
|
3410 } |
|
3411 if (tp1 == NULL) { |
|
3412 SCTP_STAT_INCR(sctps_pdrptsnnf); |
|
3413 } |
|
3414 if ((tp1) && (tp1->sent < SCTP_DATAGRAM_ACKED)) { |
|
3415 uint8_t *ddp; |
|
3416 |
|
3417 if (((flg & SCTP_BADCRC) == 0) && |
|
3418 ((flg & SCTP_FROM_MIDDLE_BOX) == 0)) { |
|
3419 return (0); |
|
3420 } |
|
3421 if ((stcb->asoc.peers_rwnd == 0) && |
|
3422 ((flg & SCTP_FROM_MIDDLE_BOX) == 0)) { |
|
3423 SCTP_STAT_INCR(sctps_pdrpdiwnp); |
|
3424 return (0); |
|
3425 } |
|
3426 if (stcb->asoc.peers_rwnd == 0 && |
|
3427 (flg & SCTP_FROM_MIDDLE_BOX)) { |
|
3428 SCTP_STAT_INCR(sctps_pdrpdizrw); |
|
3429 return (0); |
|
3430 } |
|
3431 ddp = (uint8_t *) (mtod(tp1->data, caddr_t) + |
|
3432 sizeof(struct sctp_data_chunk)); |
|
3433 { |
|
3434 unsigned int iii; |
|
3435 |
|
3436 for (iii = 0; iii < sizeof(desc->data_bytes); |
|
3437 iii++) { |
|
3438 if (ddp[iii] != desc->data_bytes[iii]) { |
|
3439 SCTP_STAT_INCR(sctps_pdrpbadd); |
|
3440 return (-1); |
|
3441 } |
|
3442 } |
|
3443 } |
|
3444 |
|
3445 if (tp1->do_rtt) { |
|
3446 /* |
|
3447 * this guy had a RTO calculation |
|
3448 * pending on it, cancel it |
|
3449 */ |
|
3450 if (tp1->whoTo->rto_needed == 0) { |
|
3451 tp1->whoTo->rto_needed = 1; |
|
3452 } |
|
3453 tp1->do_rtt = 0; |
|
3454 } |
|
3455 SCTP_STAT_INCR(sctps_pdrpmark); |
|
3456 if (tp1->sent != SCTP_DATAGRAM_RESEND) |
|
3457 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
3458 /* |
|
3459 * mark it as if we were doing a FR, since |
|
3460 * we will be getting gap ack reports behind |
|
3461 * the info from the router. |
|
3462 */ |
|
3463 tp1->rec.data.doing_fast_retransmit = 1; |
|
3464 /* |
|
3465 * mark the tsn with what sequences can |
|
3466 * cause a new FR. |
|
3467 */ |
|
3468 if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { |
|
3469 tp1->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; |
|
3470 } else { |
|
3471 tp1->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq; |
|
3472 } |
|
3473 |
|
3474 /* restart the timer */ |
|
3475 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, |
|
3476 stcb, tp1->whoTo, SCTP_FROM_SCTP_INPUT+SCTP_LOC_24); |
|
3477 sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, |
|
3478 stcb, tp1->whoTo); |
|
3479 |
|
3480 /* fix counts and things */ |
|
3481 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
|
3482 sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PDRP, |
|
3483 tp1->whoTo->flight_size, |
|
3484 tp1->book_size, |
|
3485 (uintptr_t)stcb, |
|
3486 tp1->rec.data.TSN_seq); |
|
3487 } |
|
3488 if (tp1->sent < SCTP_DATAGRAM_RESEND) { |
|
3489 sctp_flight_size_decrease(tp1); |
|
3490 sctp_total_flight_decrease(stcb, tp1); |
|
3491 } |
|
3492 tp1->sent = SCTP_DATAGRAM_RESEND; |
|
3493 } { |
|
3494 /* audit code */ |
|
3495 unsigned int audit; |
|
3496 |
|
3497 audit = 0; |
|
3498 TAILQ_FOREACH(tp1, &stcb->asoc.sent_queue, sctp_next) { |
|
3499 if (tp1->sent == SCTP_DATAGRAM_RESEND) |
|
3500 audit++; |
|
3501 } |
|
3502 TAILQ_FOREACH(tp1, &stcb->asoc.control_send_queue, |
|
3503 sctp_next) { |
|
3504 if (tp1->sent == SCTP_DATAGRAM_RESEND) |
|
3505 audit++; |
|
3506 } |
|
3507 if (audit != stcb->asoc.sent_queue_retran_cnt) { |
|
3508 SCTP_PRINTF("**Local Audit finds cnt:%d asoc cnt:%d\n", |
|
3509 audit, stcb->asoc.sent_queue_retran_cnt); |
|
3510 #ifndef SCTP_AUDITING_ENABLED |
|
3511 stcb->asoc.sent_queue_retran_cnt = audit; |
|
3512 #endif |
|
3513 } |
|
3514 } |
|
3515 } |
|
3516 break; |
|
3517 case SCTP_ASCONF: |
|
3518 { |
|
3519 struct sctp_tmit_chunk *asconf; |
|
3520 |
|
3521 TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue, |
|
3522 sctp_next) { |
|
3523 if (asconf->rec.chunk_id.id == SCTP_ASCONF) { |
|
3524 break; |
|
3525 } |
|
3526 } |
|
3527 if (asconf) { |
|
3528 if (asconf->sent != SCTP_DATAGRAM_RESEND) |
|
3529 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
3530 asconf->sent = SCTP_DATAGRAM_RESEND; |
|
3531 asconf->snd_count--; |
|
3532 } |
|
3533 } |
|
3534 break; |
|
3535 case SCTP_INITIATION: |
|
3536 /* resend the INIT */ |
|
3537 stcb->asoc.dropped_special_cnt++; |
|
3538 if (stcb->asoc.dropped_special_cnt < SCTP_RETRY_DROPPED_THRESH) { |
|
3539 /* |
|
3540 * If we can get it in, in a few attempts we do |
|
3541 * this, otherwise we let the timer fire. |
|
3542 */ |
|
3543 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, |
|
3544 stcb, net, SCTP_FROM_SCTP_INPUT+SCTP_LOC_25); |
|
3545 sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); |
|
3546 } |
|
3547 break; |
|
3548 case SCTP_SELECTIVE_ACK: |
|
3549 case SCTP_NR_SELECTIVE_ACK: |
|
3550 /* resend the sack */ |
|
3551 sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); |
|
3552 break; |
|
3553 case SCTP_HEARTBEAT_REQUEST: |
|
3554 /* resend a demand HB */ |
|
3555 if ((stcb->asoc.overall_error_count + 3) < stcb->asoc.max_send_times) { |
|
3556 /* Only retransmit if we KNOW we wont destroy the tcb */ |
|
3557 sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
|
3558 } |
|
3559 break; |
|
3560 case SCTP_SHUTDOWN: |
|
3561 sctp_send_shutdown(stcb, net); |
|
3562 break; |
|
3563 case SCTP_SHUTDOWN_ACK: |
|
3564 sctp_send_shutdown_ack(stcb, net); |
|
3565 break; |
|
3566 case SCTP_COOKIE_ECHO: |
|
3567 { |
|
3568 struct sctp_tmit_chunk *cookie; |
|
3569 |
|
3570 cookie = NULL; |
|
3571 TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, |
|
3572 sctp_next) { |
|
3573 if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { |
|
3574 break; |
|
3575 } |
|
3576 } |
|
3577 if (cookie) { |
|
3578 if (cookie->sent != SCTP_DATAGRAM_RESEND) |
|
3579 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
3580 cookie->sent = SCTP_DATAGRAM_RESEND; |
|
3581 sctp_stop_all_cookie_timers(stcb); |
|
3582 } |
|
3583 } |
|
3584 break; |
|
3585 case SCTP_COOKIE_ACK: |
|
3586 sctp_send_cookie_ack(stcb); |
|
3587 break; |
|
3588 case SCTP_ASCONF_ACK: |
|
3589 /* resend last asconf ack */ |
|
3590 sctp_send_asconf_ack(stcb); |
|
3591 break; |
|
3592 case SCTP_FORWARD_CUM_TSN: |
|
3593 send_forward_tsn(stcb, &stcb->asoc); |
|
3594 break; |
|
3595 /* can't do anything with these */ |
|
3596 case SCTP_PACKET_DROPPED: |
|
3597 case SCTP_INITIATION_ACK: /* this should not happen */ |
|
3598 case SCTP_HEARTBEAT_ACK: |
|
3599 case SCTP_ABORT_ASSOCIATION: |
|
3600 case SCTP_OPERATION_ERROR: |
|
3601 case SCTP_SHUTDOWN_COMPLETE: |
|
3602 case SCTP_ECN_ECHO: |
|
3603 case SCTP_ECN_CWR: |
|
3604 default: |
|
3605 break; |
|
3606 } |
|
3607 return (0); |
|
3608 } |
|
3609 |
|
3610 void |
|
3611 sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list) |
|
3612 { |
|
3613 uint32_t i; |
|
3614 uint16_t temp; |
|
3615 |
|
3616 /* |
|
3617 * We set things to 0xffff since this is the last delivered sequence |
|
3618 * and we will be sending in 0 after the reset. |
|
3619 */ |
|
3620 |
|
3621 if (number_entries) { |
|
3622 for (i = 0; i < number_entries; i++) { |
|
3623 temp = ntohs(list[i]); |
|
3624 if (temp >= stcb->asoc.streamincnt) { |
|
3625 continue; |
|
3626 } |
|
3627 stcb->asoc.strmin[temp].last_sequence_delivered = 0xffff; |
|
3628 } |
|
3629 } else { |
|
3630 list = NULL; |
|
3631 for (i = 0; i < stcb->asoc.streamincnt; i++) { |
|
3632 stcb->asoc.strmin[i].last_sequence_delivered = 0xffff; |
|
3633 } |
|
3634 } |
|
3635 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); |
|
3636 } |
|
3637 |
|
3638 static void |
|
3639 sctp_reset_out_streams(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *list) |
|
3640 { |
|
3641 uint32_t i; |
|
3642 uint16_t temp; |
|
3643 |
|
3644 if (number_entries > 0) { |
|
3645 for (i = 0; i < number_entries; i++) { |
|
3646 temp = ntohs(list[i]); |
|
3647 if (temp >= stcb->asoc.streamoutcnt) { |
|
3648 /* no such stream */ |
|
3649 continue; |
|
3650 } |
|
3651 stcb->asoc.strmout[temp].next_sequence_send = 0; |
|
3652 } |
|
3653 } else { |
|
3654 for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
|
3655 stcb->asoc.strmout[i].next_sequence_send = 0; |
|
3656 } |
|
3657 } |
|
3658 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); |
|
3659 } |
|
3660 |
|
3661 |
|
3662 struct sctp_stream_reset_out_request * |
|
3663 sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chunk **bchk) |
|
3664 { |
|
3665 struct sctp_association *asoc; |
|
3666 struct sctp_chunkhdr *ch; |
|
3667 struct sctp_stream_reset_out_request *r; |
|
3668 struct sctp_tmit_chunk *chk; |
|
3669 int len, clen; |
|
3670 |
|
3671 asoc = &stcb->asoc; |
|
3672 if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { |
|
3673 asoc->stream_reset_outstanding = 0; |
|
3674 return (NULL); |
|
3675 } |
|
3676 if (stcb->asoc.str_reset == NULL) { |
|
3677 asoc->stream_reset_outstanding = 0; |
|
3678 return (NULL); |
|
3679 } |
|
3680 chk = stcb->asoc.str_reset; |
|
3681 if (chk->data == NULL) { |
|
3682 return (NULL); |
|
3683 } |
|
3684 if (bchk) { |
|
3685 /* he wants a copy of the chk pointer */ |
|
3686 *bchk = chk; |
|
3687 } |
|
3688 clen = chk->send_size; |
|
3689 ch = mtod(chk->data, struct sctp_chunkhdr *); |
|
3690 r = (struct sctp_stream_reset_out_request *)(ch + 1); |
|
3691 if (ntohl(r->request_seq) == seq) { |
|
3692 /* found it */ |
|
3693 return (r); |
|
3694 } |
|
3695 len = SCTP_SIZE32(ntohs(r->ph.param_length)); |
|
3696 if (clen > (len + (int)sizeof(struct sctp_chunkhdr))) { |
|
3697 /* move to the next one, there can only be a max of two */ |
|
3698 r = (struct sctp_stream_reset_out_request *)((caddr_t)r + len); |
|
3699 if (ntohl(r->request_seq) == seq) { |
|
3700 return (r); |
|
3701 } |
|
3702 } |
|
3703 /* that seq is not here */ |
|
3704 return (NULL); |
|
3705 } |
|
3706 |
|
3707 static void |
|
3708 sctp_clean_up_stream_reset(struct sctp_tcb *stcb) |
|
3709 { |
|
3710 struct sctp_association *asoc; |
|
3711 struct sctp_tmit_chunk *chk = stcb->asoc.str_reset; |
|
3712 |
|
3713 if (stcb->asoc.str_reset == NULL) { |
|
3714 return; |
|
3715 } |
|
3716 asoc = &stcb->asoc; |
|
3717 |
|
3718 sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo, SCTP_FROM_SCTP_INPUT+SCTP_LOC_26); |
|
3719 TAILQ_REMOVE(&asoc->control_send_queue, |
|
3720 chk, |
|
3721 sctp_next); |
|
3722 if (chk->data) { |
|
3723 sctp_m_freem(chk->data); |
|
3724 chk->data = NULL; |
|
3725 } |
|
3726 asoc->ctrl_queue_cnt--; |
|
3727 sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
|
3728 /*sa_ignore NO_NULL_CHK*/ |
|
3729 stcb->asoc.str_reset = NULL; |
|
3730 } |
|
3731 |
|
3732 |
|
3733 static int |
|
3734 sctp_handle_stream_reset_response(struct sctp_tcb *stcb, |
|
3735 uint32_t seq, uint32_t action, |
|
3736 struct sctp_stream_reset_response *respin) |
|
3737 { |
|
3738 uint16_t type; |
|
3739 int lparm_len; |
|
3740 struct sctp_association *asoc = &stcb->asoc; |
|
3741 struct sctp_tmit_chunk *chk; |
|
3742 struct sctp_stream_reset_out_request *srparam; |
|
3743 uint32_t number_entries; |
|
3744 |
|
3745 if (asoc->stream_reset_outstanding == 0) { |
|
3746 /* duplicate */ |
|
3747 return (0); |
|
3748 } |
|
3749 if (seq == stcb->asoc.str_reset_seq_out) { |
|
3750 srparam = sctp_find_stream_reset(stcb, seq, &chk); |
|
3751 if (srparam) { |
|
3752 stcb->asoc.str_reset_seq_out++; |
|
3753 type = ntohs(srparam->ph.param_type); |
|
3754 lparm_len = ntohs(srparam->ph.param_length); |
|
3755 if (type == SCTP_STR_RESET_OUT_REQUEST) { |
|
3756 number_entries = (lparm_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t); |
|
3757 asoc->stream_reset_out_is_outstanding = 0; |
|
3758 if (asoc->stream_reset_outstanding) |
|
3759 asoc->stream_reset_outstanding--; |
|
3760 if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { |
|
3761 /* do it */ |
|
3762 sctp_reset_out_streams(stcb, number_entries, srparam->list_of_streams); |
|
3763 } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { |
|
3764 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_OUT, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED); |
|
3765 } else { |
|
3766 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED); |
|
3767 } |
|
3768 } else if (type == SCTP_STR_RESET_IN_REQUEST) { |
|
3769 /* Answered my request */ |
|
3770 number_entries = (lparm_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t); |
|
3771 if (asoc->stream_reset_outstanding) |
|
3772 asoc->stream_reset_outstanding--; |
|
3773 if (action == SCTP_STREAM_RESET_RESULT_DENIED) { |
|
3774 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_IN, stcb, |
|
3775 number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED); |
|
3776 } else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) { |
|
3777 sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, |
|
3778 number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED); |
|
3779 } |
|
3780 } else if (type == SCTP_STR_RESET_ADD_OUT_STREAMS) { |
|
3781 /* Ok we now may have more streams */ |
|
3782 int num_stream; |
|
3783 |
|
3784 num_stream = stcb->asoc.strm_pending_add_size; |
|
3785 if (num_stream > (stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt)) { |
|
3786 /* TSNH */ |
|
3787 num_stream = stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt; |
|
3788 } |
|
3789 stcb->asoc.strm_pending_add_size = 0; |
|
3790 if (asoc->stream_reset_outstanding) |
|
3791 asoc->stream_reset_outstanding--; |
|
3792 if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { |
|
3793 /* Put the new streams into effect */ |
|
3794 stcb->asoc.streamoutcnt += num_stream; |
|
3795 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); |
|
3796 } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { |
|
3797 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, |
|
3798 SCTP_STREAM_CHANGE_DENIED); |
|
3799 } else { |
|
3800 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, |
|
3801 SCTP_STREAM_CHANGE_FAILED); |
|
3802 } |
|
3803 } else if (type == SCTP_STR_RESET_ADD_IN_STREAMS) { |
|
3804 if (asoc->stream_reset_outstanding) |
|
3805 asoc->stream_reset_outstanding--; |
|
3806 if (action == SCTP_STREAM_RESET_RESULT_DENIED) { |
|
3807 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, |
|
3808 SCTP_STREAM_CHANGE_DENIED); |
|
3809 } else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) { |
|
3810 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, |
|
3811 SCTP_STREAM_CHANGE_FAILED); |
|
3812 } |
|
3813 } else if (type == SCTP_STR_RESET_TSN_REQUEST) { |
|
3814 /** |
|
3815 * a) Adopt the new in tsn. |
|
3816 * b) reset the map |
|
3817 * c) Adopt the new out-tsn |
|
3818 */ |
|
3819 struct sctp_stream_reset_response_tsn *resp; |
|
3820 struct sctp_forward_tsn_chunk fwdtsn; |
|
3821 int abort_flag = 0; |
|
3822 if (respin == NULL) { |
|
3823 /* huh ? */ |
|
3824 return (0); |
|
3825 } |
|
3826 if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { |
|
3827 resp = (struct sctp_stream_reset_response_tsn *)respin; |
|
3828 asoc->stream_reset_outstanding--; |
|
3829 fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk)); |
|
3830 fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN; |
|
3831 fwdtsn.new_cumulative_tsn = htonl(ntohl(resp->senders_next_tsn) - 1); |
|
3832 sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0); |
|
3833 if (abort_flag) { |
|
3834 return (1); |
|
3835 } |
|
3836 stcb->asoc.highest_tsn_inside_map = (ntohl(resp->senders_next_tsn) - 1); |
|
3837 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { |
|
3838 sctp_log_map(0, 7, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); |
|
3839 } |
|
3840 |
|
3841 stcb->asoc.tsn_last_delivered = stcb->asoc.cumulative_tsn = stcb->asoc.highest_tsn_inside_map; |
|
3842 stcb->asoc.mapping_array_base_tsn = ntohl(resp->senders_next_tsn); |
|
3843 memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size); |
|
3844 |
|
3845 stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map; |
|
3846 memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size); |
|
3847 |
|
3848 stcb->asoc.sending_seq = ntohl(resp->receivers_next_tsn); |
|
3849 stcb->asoc.last_acked_seq = stcb->asoc.cumulative_tsn; |
|
3850 |
|
3851 sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); |
|
3852 sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); |
|
3853 sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0); |
|
3854 } else if (action == SCTP_STREAM_RESET_RESULT_DENIED) { |
|
3855 sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), |
|
3856 SCTP_ASSOC_RESET_DENIED); |
|
3857 } else { |
|
3858 sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), |
|
3859 SCTP_ASSOC_RESET_FAILED); |
|
3860 } |
|
3861 } |
|
3862 /* get rid of the request and get the request flags */ |
|
3863 if (asoc->stream_reset_outstanding == 0) { |
|
3864 sctp_clean_up_stream_reset(stcb); |
|
3865 } |
|
3866 } |
|
3867 } |
|
3868 return (0); |
|
3869 } |
|
3870 |
|
3871 static void |
|
3872 sctp_handle_str_reset_request_in(struct sctp_tcb *stcb, |
|
3873 struct sctp_tmit_chunk *chk, |
|
3874 struct sctp_stream_reset_in_request *req, int trunc) |
|
3875 { |
|
3876 uint32_t seq; |
|
3877 int len, i; |
|
3878 int number_entries; |
|
3879 uint16_t temp; |
|
3880 |
|
3881 /* |
|
3882 * peer wants me to send a str-reset to him for my outgoing seq's if |
|
3883 * seq_in is right. |
|
3884 */ |
|
3885 struct sctp_association *asoc = &stcb->asoc; |
|
3886 |
|
3887 seq = ntohl(req->request_seq); |
|
3888 if (asoc->str_reset_seq_in == seq) { |
|
3889 asoc->last_reset_action[1] = asoc->last_reset_action[0]; |
|
3890 if (!(asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) { |
|
3891 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
3892 } else if (trunc) { |
|
3893 /* Can't do it, since they exceeded our buffer size */ |
|
3894 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
3895 } else if (stcb->asoc.stream_reset_out_is_outstanding == 0) { |
|
3896 len = ntohs(req->ph.param_length); |
|
3897 number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t)); |
|
3898 for (i = 0; i < number_entries; i++) { |
|
3899 temp = ntohs(req->list_of_streams[i]); |
|
3900 req->list_of_streams[i] = temp; |
|
3901 } |
|
3902 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
3903 sctp_add_stream_reset_out(chk, number_entries, req->list_of_streams, |
|
3904 asoc->str_reset_seq_out, |
|
3905 seq, (asoc->sending_seq - 1)); |
|
3906 asoc->stream_reset_out_is_outstanding = 1; |
|
3907 asoc->str_reset = chk; |
|
3908 sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); |
|
3909 stcb->asoc.stream_reset_outstanding++; |
|
3910 } else { |
|
3911 /* Can't do it, since we have sent one out */ |
|
3912 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS; |
|
3913 } |
|
3914 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
3915 asoc->str_reset_seq_in++; |
|
3916 } else if (asoc->str_reset_seq_in - 1 == seq) { |
|
3917 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
3918 } else if (asoc->str_reset_seq_in - 2 == seq) { |
|
3919 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); |
|
3920 } else { |
|
3921 sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); |
|
3922 } |
|
3923 } |
|
3924 |
|
3925 static int |
|
3926 sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb, |
|
3927 struct sctp_tmit_chunk *chk, |
|
3928 struct sctp_stream_reset_tsn_request *req) |
|
3929 { |
|
3930 /* reset all in and out and update the tsn */ |
|
3931 /* |
|
3932 * A) reset my str-seq's on in and out. B) Select a receive next, |
|
3933 * and set cum-ack to it. Also process this selected number as a |
|
3934 * fwd-tsn as well. C) set in the response my next sending seq. |
|
3935 */ |
|
3936 struct sctp_forward_tsn_chunk fwdtsn; |
|
3937 struct sctp_association *asoc = &stcb->asoc; |
|
3938 int abort_flag = 0; |
|
3939 uint32_t seq; |
|
3940 |
|
3941 seq = ntohl(req->request_seq); |
|
3942 if (asoc->str_reset_seq_in == seq) { |
|
3943 asoc->last_reset_action[1] = stcb->asoc.last_reset_action[0]; |
|
3944 if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { |
|
3945 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
3946 } else { |
|
3947 fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk)); |
|
3948 fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN; |
|
3949 fwdtsn.ch.chunk_flags = 0; |
|
3950 fwdtsn.new_cumulative_tsn = htonl(stcb->asoc.highest_tsn_inside_map + 1); |
|
3951 sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0); |
|
3952 if (abort_flag) { |
|
3953 return (1); |
|
3954 } |
|
3955 asoc->highest_tsn_inside_map += SCTP_STREAM_RESET_TSN_DELTA; |
|
3956 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { |
|
3957 sctp_log_map(0, 10, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); |
|
3958 } |
|
3959 asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->highest_tsn_inside_map; |
|
3960 asoc->mapping_array_base_tsn = asoc->highest_tsn_inside_map + 1; |
|
3961 memset(asoc->mapping_array, 0, asoc->mapping_array_size); |
|
3962 asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map; |
|
3963 memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); |
|
3964 atomic_add_int(&asoc->sending_seq, 1); |
|
3965 /* save off historical data for retrans */ |
|
3966 asoc->last_sending_seq[1] = asoc->last_sending_seq[0]; |
|
3967 asoc->last_sending_seq[0] = asoc->sending_seq; |
|
3968 asoc->last_base_tsnsent[1] = asoc->last_base_tsnsent[0]; |
|
3969 asoc->last_base_tsnsent[0] = asoc->mapping_array_base_tsn; |
|
3970 sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL); |
|
3971 sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL); |
|
3972 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
3973 sctp_notify_stream_reset_tsn(stcb, asoc->sending_seq, (asoc->mapping_array_base_tsn + 1), 0); |
|
3974 } |
|
3975 sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0], |
|
3976 asoc->last_sending_seq[0], asoc->last_base_tsnsent[0]); |
|
3977 asoc->str_reset_seq_in++; |
|
3978 } else if (asoc->str_reset_seq_in - 1 == seq) { |
|
3979 sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0], |
|
3980 asoc->last_sending_seq[0], asoc->last_base_tsnsent[0]); |
|
3981 } else if (asoc->str_reset_seq_in - 2 == seq) { |
|
3982 sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[1], |
|
3983 asoc->last_sending_seq[1], asoc->last_base_tsnsent[1]); |
|
3984 } else { |
|
3985 sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); |
|
3986 } |
|
3987 return (0); |
|
3988 } |
|
3989 |
|
3990 static void |
|
3991 sctp_handle_str_reset_request_out(struct sctp_tcb *stcb, |
|
3992 struct sctp_tmit_chunk *chk, |
|
3993 struct sctp_stream_reset_out_request *req, int trunc) |
|
3994 { |
|
3995 uint32_t seq, tsn; |
|
3996 int number_entries, len; |
|
3997 struct sctp_association *asoc = &stcb->asoc; |
|
3998 |
|
3999 seq = ntohl(req->request_seq); |
|
4000 |
|
4001 /* now if its not a duplicate we process it */ |
|
4002 if (asoc->str_reset_seq_in == seq) { |
|
4003 len = ntohs(req->ph.param_length); |
|
4004 number_entries = ((len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t)); |
|
4005 /* |
|
4006 * the sender is resetting, handle the list issue.. we must |
|
4007 * a) verify if we can do the reset, if so no problem b) If |
|
4008 * we can't do the reset we must copy the request. c) queue |
|
4009 * it, and setup the data in processor to trigger it off |
|
4010 * when needed and dequeue all the queued data. |
|
4011 */ |
|
4012 tsn = ntohl(req->send_reset_at_tsn); |
|
4013 |
|
4014 /* move the reset action back one */ |
|
4015 asoc->last_reset_action[1] = asoc->last_reset_action[0]; |
|
4016 if (!(asoc->local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) { |
|
4017 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4018 } else if (trunc) { |
|
4019 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4020 } else if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) { |
|
4021 /* we can do it now */ |
|
4022 sctp_reset_in_stream(stcb, number_entries, req->list_of_streams); |
|
4023 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
4024 } else { |
|
4025 /* |
|
4026 * we must queue it up and thus wait for the TSN's |
|
4027 * to arrive that are at or before tsn |
|
4028 */ |
|
4029 struct sctp_stream_reset_list *liste; |
|
4030 int siz; |
|
4031 |
|
4032 siz = sizeof(struct sctp_stream_reset_list) + (number_entries * sizeof(uint16_t)); |
|
4033 SCTP_MALLOC(liste, struct sctp_stream_reset_list *, |
|
4034 siz, SCTP_M_STRESET); |
|
4035 if (liste == NULL) { |
|
4036 /* gak out of memory */ |
|
4037 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4038 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4039 return; |
|
4040 } |
|
4041 liste->tsn = tsn; |
|
4042 liste->number_entries = number_entries; |
|
4043 memcpy(&liste->list_of_streams, req->list_of_streams, number_entries * sizeof(uint16_t)); |
|
4044 TAILQ_INSERT_TAIL(&asoc->resetHead, liste, next_resp); |
|
4045 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
4046 } |
|
4047 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4048 asoc->str_reset_seq_in++; |
|
4049 } else if ((asoc->str_reset_seq_in - 1) == seq) { |
|
4050 /* |
|
4051 * one seq back, just echo back last action since my |
|
4052 * response was lost. |
|
4053 */ |
|
4054 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4055 } else if ((asoc->str_reset_seq_in - 2) == seq) { |
|
4056 /* |
|
4057 * two seq back, just echo back last action since my |
|
4058 * response was lost. |
|
4059 */ |
|
4060 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); |
|
4061 } else { |
|
4062 sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); |
|
4063 } |
|
4064 } |
|
4065 |
|
4066 static void |
|
4067 sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, |
|
4068 struct sctp_stream_reset_add_strm *str_add) |
|
4069 { |
|
4070 /* |
|
4071 * Peer is requesting to add more streams. |
|
4072 * If its within our max-streams we will |
|
4073 * allow it. |
|
4074 */ |
|
4075 uint32_t num_stream, i; |
|
4076 uint32_t seq; |
|
4077 struct sctp_association *asoc = &stcb->asoc; |
|
4078 struct sctp_queued_to_read *ctl, *nctl; |
|
4079 |
|
4080 /* Get the number. */ |
|
4081 seq = ntohl(str_add->request_seq); |
|
4082 num_stream = ntohs(str_add->number_of_streams); |
|
4083 /* Now what would be the new total? */ |
|
4084 if (asoc->str_reset_seq_in == seq) { |
|
4085 num_stream += stcb->asoc.streamincnt; |
|
4086 stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; |
|
4087 if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { |
|
4088 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4089 } else if ((num_stream > stcb->asoc.max_inbound_streams) || |
|
4090 (num_stream > 0xffff)) { |
|
4091 /* We must reject it they ask for to many */ |
|
4092 denied: |
|
4093 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4094 } else { |
|
4095 /* Ok, we can do that :-) */ |
|
4096 struct sctp_stream_in *oldstrm; |
|
4097 |
|
4098 /* save off the old */ |
|
4099 oldstrm = stcb->asoc.strmin; |
|
4100 SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *, |
|
4101 (num_stream * sizeof(struct sctp_stream_in)), |
|
4102 SCTP_M_STRMI); |
|
4103 if (stcb->asoc.strmin == NULL) { |
|
4104 stcb->asoc.strmin = oldstrm; |
|
4105 goto denied; |
|
4106 } |
|
4107 /* copy off the old data */ |
|
4108 for (i = 0; i < stcb->asoc.streamincnt; i++) { |
|
4109 TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); |
|
4110 stcb->asoc.strmin[i].stream_no = i; |
|
4111 stcb->asoc.strmin[i].last_sequence_delivered = oldstrm[i].last_sequence_delivered; |
|
4112 stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started; |
|
4113 /* now anything on those queues? */ |
|
4114 TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next, nctl) { |
|
4115 TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next); |
|
4116 TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next); |
|
4117 } |
|
4118 } |
|
4119 /* Init the new streams */ |
|
4120 for (i = stcb->asoc.streamincnt; i < num_stream; i++) { |
|
4121 TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); |
|
4122 stcb->asoc.strmin[i].stream_no = i; |
|
4123 stcb->asoc.strmin[i].last_sequence_delivered = 0xffff; |
|
4124 stcb->asoc.strmin[i].delivery_started = 0; |
|
4125 } |
|
4126 SCTP_FREE(oldstrm, SCTP_M_STRMI); |
|
4127 /* update the size */ |
|
4128 stcb->asoc.streamincnt = num_stream; |
|
4129 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
4130 sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0); |
|
4131 } |
|
4132 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4133 asoc->str_reset_seq_in++; |
|
4134 } else if ((asoc->str_reset_seq_in - 1) == seq) { |
|
4135 /* |
|
4136 * one seq back, just echo back last action since my |
|
4137 * response was lost. |
|
4138 */ |
|
4139 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4140 } else if ((asoc->str_reset_seq_in - 2) == seq) { |
|
4141 /* |
|
4142 * two seq back, just echo back last action since my |
|
4143 * response was lost. |
|
4144 */ |
|
4145 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); |
|
4146 } else { |
|
4147 sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); |
|
4148 |
|
4149 } |
|
4150 } |
|
4151 |
|
4152 static void |
|
4153 sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, |
|
4154 struct sctp_stream_reset_add_strm *str_add) |
|
4155 { |
|
4156 /* |
|
4157 * Peer is requesting to add more streams. |
|
4158 * If its within our max-streams we will |
|
4159 * allow it. |
|
4160 */ |
|
4161 uint16_t num_stream; |
|
4162 uint32_t seq; |
|
4163 struct sctp_association *asoc = &stcb->asoc; |
|
4164 |
|
4165 /* Get the number. */ |
|
4166 seq = ntohl(str_add->request_seq); |
|
4167 num_stream = ntohs(str_add->number_of_streams); |
|
4168 /* Now what would be the new total? */ |
|
4169 if (asoc->str_reset_seq_in == seq) { |
|
4170 stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0]; |
|
4171 if (!(asoc->local_strreset_support & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { |
|
4172 asoc->last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4173 } else if (stcb->asoc.stream_reset_outstanding) { |
|
4174 /* We must reject it we have something pending */ |
|
4175 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_ERR_IN_PROGRESS; |
|
4176 } else { |
|
4177 /* Ok, we can do that :-) */ |
|
4178 int mychk; |
|
4179 mychk = stcb->asoc.streamoutcnt; |
|
4180 mychk += num_stream; |
|
4181 if (mychk < 0x10000) { |
|
4182 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_PERFORMED; |
|
4183 if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, 1, num_stream, 0, 1)) { |
|
4184 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4185 } |
|
4186 } else { |
|
4187 stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_RESULT_DENIED; |
|
4188 } |
|
4189 } |
|
4190 sctp_add_stream_reset_result(chk, seq, stcb->asoc.last_reset_action[0]); |
|
4191 asoc->str_reset_seq_in++; |
|
4192 } else if ((asoc->str_reset_seq_in - 1) == seq) { |
|
4193 /* |
|
4194 * one seq back, just echo back last action since my |
|
4195 * response was lost. |
|
4196 */ |
|
4197 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]); |
|
4198 } else if ((asoc->str_reset_seq_in - 2) == seq) { |
|
4199 /* |
|
4200 * two seq back, just echo back last action since my |
|
4201 * response was lost. |
|
4202 */ |
|
4203 sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]); |
|
4204 } else { |
|
4205 sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_RESULT_ERR_BAD_SEQNO); |
|
4206 } |
|
4207 } |
|
4208 |
|
4209 #if !defined(__Panda__) |
|
4210 #ifdef __GNUC__ |
|
4211 __attribute__ ((noinline)) |
|
4212 #endif |
|
4213 #endif |
|
4214 static int |
|
4215 sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, |
|
4216 struct sctp_chunkhdr *ch_req) |
|
4217 { |
|
4218 int chk_length, param_len, ptype; |
|
4219 struct sctp_paramhdr pstore; |
|
4220 uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; |
|
4221 uint32_t seq = 0; |
|
4222 int num_req = 0; |
|
4223 int trunc = 0; |
|
4224 struct sctp_tmit_chunk *chk; |
|
4225 struct sctp_chunkhdr *ch; |
|
4226 struct sctp_paramhdr *ph; |
|
4227 int ret_code = 0; |
|
4228 int num_param = 0; |
|
4229 |
|
4230 /* now it may be a reset or a reset-response */ |
|
4231 chk_length = ntohs(ch_req->chunk_length); |
|
4232 |
|
4233 /* setup for adding the response */ |
|
4234 sctp_alloc_a_chunk(stcb, chk); |
|
4235 if (chk == NULL) { |
|
4236 return (ret_code); |
|
4237 } |
|
4238 chk->rec.chunk_id.id = SCTP_STREAM_RESET; |
|
4239 chk->rec.chunk_id.can_take_data = 0; |
|
4240 chk->asoc = &stcb->asoc; |
|
4241 chk->no_fr_allowed = 0; |
|
4242 chk->book_size = chk->send_size = sizeof(struct sctp_chunkhdr); |
|
4243 chk->book_size_scale = 0; |
|
4244 chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
|
4245 if (chk->data == NULL) { |
|
4246 strres_nochunk: |
|
4247 if (chk->data) { |
|
4248 sctp_m_freem(chk->data); |
|
4249 chk->data = NULL; |
|
4250 } |
|
4251 sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
|
4252 return (ret_code); |
|
4253 } |
|
4254 SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
|
4255 |
|
4256 /* setup chunk parameters */ |
|
4257 chk->sent = SCTP_DATAGRAM_UNSENT; |
|
4258 chk->snd_count = 0; |
|
4259 chk->whoTo = NULL; |
|
4260 |
|
4261 ch = mtod(chk->data, struct sctp_chunkhdr *); |
|
4262 ch->chunk_type = SCTP_STREAM_RESET; |
|
4263 ch->chunk_flags = 0; |
|
4264 ch->chunk_length = htons(chk->send_size); |
|
4265 SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); |
|
4266 offset += sizeof(struct sctp_chunkhdr); |
|
4267 while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { |
|
4268 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *)&pstore); |
|
4269 if (ph == NULL) |
|
4270 break; |
|
4271 param_len = ntohs(ph->param_length); |
|
4272 if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { |
|
4273 /* bad param */ |
|
4274 break; |
|
4275 } |
|
4276 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), |
|
4277 (uint8_t *)&cstore); |
|
4278 ptype = ntohs(ph->param_type); |
|
4279 num_param++; |
|
4280 if (param_len > (int)sizeof(cstore)) { |
|
4281 trunc = 1; |
|
4282 } else { |
|
4283 trunc = 0; |
|
4284 } |
|
4285 if (num_param > SCTP_MAX_RESET_PARAMS) { |
|
4286 /* hit the max of parameters already sorry.. */ |
|
4287 break; |
|
4288 } |
|
4289 if (ptype == SCTP_STR_RESET_OUT_REQUEST) { |
|
4290 struct sctp_stream_reset_out_request *req_out; |
|
4291 req_out = (struct sctp_stream_reset_out_request *)ph; |
|
4292 num_req++; |
|
4293 if (stcb->asoc.stream_reset_outstanding) { |
|
4294 seq = ntohl(req_out->response_seq); |
|
4295 if (seq == stcb->asoc.str_reset_seq_out) { |
|
4296 /* implicit ack */ |
|
4297 (void)sctp_handle_stream_reset_response(stcb, seq, SCTP_STREAM_RESET_RESULT_PERFORMED, NULL); |
|
4298 } |
|
4299 } |
|
4300 sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc); |
|
4301 } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { |
|
4302 struct sctp_stream_reset_add_strm *str_add; |
|
4303 str_add = (struct sctp_stream_reset_add_strm *)ph; |
|
4304 num_req++; |
|
4305 sctp_handle_str_reset_add_strm(stcb, chk, str_add); |
|
4306 } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { |
|
4307 struct sctp_stream_reset_add_strm *str_add; |
|
4308 str_add = (struct sctp_stream_reset_add_strm *)ph; |
|
4309 num_req++; |
|
4310 sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); |
|
4311 } else if (ptype == SCTP_STR_RESET_IN_REQUEST) { |
|
4312 struct sctp_stream_reset_in_request *req_in; |
|
4313 num_req++; |
|
4314 req_in = (struct sctp_stream_reset_in_request *)ph; |
|
4315 sctp_handle_str_reset_request_in(stcb, chk, req_in, trunc); |
|
4316 } else if (ptype == SCTP_STR_RESET_TSN_REQUEST) { |
|
4317 struct sctp_stream_reset_tsn_request *req_tsn; |
|
4318 num_req++; |
|
4319 req_tsn = (struct sctp_stream_reset_tsn_request *)ph; |
|
4320 if (sctp_handle_str_reset_request_tsn(stcb, chk, req_tsn)) { |
|
4321 ret_code = 1; |
|
4322 goto strres_nochunk; |
|
4323 } |
|
4324 /* no more */ |
|
4325 break; |
|
4326 } else if (ptype == SCTP_STR_RESET_RESPONSE) { |
|
4327 struct sctp_stream_reset_response *resp; |
|
4328 uint32_t result; |
|
4329 resp = (struct sctp_stream_reset_response *)ph; |
|
4330 seq = ntohl(resp->response_seq); |
|
4331 result = ntohl(resp->result); |
|
4332 if (sctp_handle_stream_reset_response(stcb, seq, result, resp)) { |
|
4333 ret_code = 1; |
|
4334 goto strres_nochunk; |
|
4335 } |
|
4336 } else { |
|
4337 break; |
|
4338 } |
|
4339 offset += SCTP_SIZE32(param_len); |
|
4340 chk_length -= SCTP_SIZE32(param_len); |
|
4341 } |
|
4342 if (num_req == 0) { |
|
4343 /* we have no response free the stuff */ |
|
4344 goto strres_nochunk; |
|
4345 } |
|
4346 /* ok we have a chunk to link in */ |
|
4347 TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, |
|
4348 chk, |
|
4349 sctp_next); |
|
4350 stcb->asoc.ctrl_queue_cnt++; |
|
4351 return (ret_code); |
|
4352 } |
|
4353 |
|
4354 /* |
|
4355 * Handle a router or endpoints report of a packet loss, there are two ways |
|
4356 * to handle this, either we get the whole packet and must disect it |
|
4357 * ourselves (possibly with truncation and or corruption) or it is a summary |
|
4358 * from a middle box that did the disectting for us. |
|
4359 */ |
|
4360 static void |
|
4361 sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp, |
|
4362 struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit) |
|
4363 { |
|
4364 uint32_t bottle_bw, on_queue; |
|
4365 uint16_t trunc_len; |
|
4366 unsigned int chlen; |
|
4367 unsigned int at; |
|
4368 struct sctp_chunk_desc desc; |
|
4369 struct sctp_chunkhdr *ch; |
|
4370 |
|
4371 chlen = ntohs(cp->ch.chunk_length); |
|
4372 chlen -= sizeof(struct sctp_pktdrop_chunk); |
|
4373 /* XXX possible chlen underflow */ |
|
4374 if (chlen == 0) { |
|
4375 ch = NULL; |
|
4376 if (cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX) |
|
4377 SCTP_STAT_INCR(sctps_pdrpbwrpt); |
|
4378 } else { |
|
4379 ch = (struct sctp_chunkhdr *)(cp->data + sizeof(struct sctphdr)); |
|
4380 chlen -= sizeof(struct sctphdr); |
|
4381 /* XXX possible chlen underflow */ |
|
4382 memset(&desc, 0, sizeof(desc)); |
|
4383 } |
|
4384 trunc_len = (uint16_t) ntohs(cp->trunc_len); |
|
4385 if (trunc_len > limit) { |
|
4386 trunc_len = limit; |
|
4387 } |
|
4388 |
|
4389 /* now the chunks themselves */ |
|
4390 while ((ch != NULL) && (chlen >= sizeof(struct sctp_chunkhdr))) { |
|
4391 desc.chunk_type = ch->chunk_type; |
|
4392 /* get amount we need to move */ |
|
4393 at = ntohs(ch->chunk_length); |
|
4394 if (at < sizeof(struct sctp_chunkhdr)) { |
|
4395 /* corrupt chunk, maybe at the end? */ |
|
4396 SCTP_STAT_INCR(sctps_pdrpcrupt); |
|
4397 break; |
|
4398 } |
|
4399 if (trunc_len == 0) { |
|
4400 /* we are supposed to have all of it */ |
|
4401 if (at > chlen) { |
|
4402 /* corrupt skip it */ |
|
4403 SCTP_STAT_INCR(sctps_pdrpcrupt); |
|
4404 break; |
|
4405 } |
|
4406 } else { |
|
4407 /* is there enough of it left ? */ |
|
4408 if (desc.chunk_type == SCTP_DATA) { |
|
4409 if (chlen < (sizeof(struct sctp_data_chunk) + |
|
4410 sizeof(desc.data_bytes))) { |
|
4411 break; |
|
4412 } |
|
4413 } else { |
|
4414 if (chlen < sizeof(struct sctp_chunkhdr)) { |
|
4415 break; |
|
4416 } |
|
4417 } |
|
4418 } |
|
4419 if (desc.chunk_type == SCTP_DATA) { |
|
4420 /* can we get out the tsn? */ |
|
4421 if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX)) |
|
4422 SCTP_STAT_INCR(sctps_pdrpmbda); |
|
4423 |
|
4424 if (chlen >= (sizeof(struct sctp_data_chunk) + sizeof(uint32_t))) { |
|
4425 /* yep */ |
|
4426 struct sctp_data_chunk *dcp; |
|
4427 uint8_t *ddp; |
|
4428 unsigned int iii; |
|
4429 |
|
4430 dcp = (struct sctp_data_chunk *)ch; |
|
4431 ddp = (uint8_t *) (dcp + 1); |
|
4432 for (iii = 0; iii < sizeof(desc.data_bytes); iii++) { |
|
4433 desc.data_bytes[iii] = ddp[iii]; |
|
4434 } |
|
4435 desc.tsn_ifany = dcp->dp.tsn; |
|
4436 } else { |
|
4437 /* nope we are done. */ |
|
4438 SCTP_STAT_INCR(sctps_pdrpnedat); |
|
4439 break; |
|
4440 } |
|
4441 } else { |
|
4442 if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX)) |
|
4443 SCTP_STAT_INCR(sctps_pdrpmbct); |
|
4444 } |
|
4445 |
|
4446 if (process_chunk_drop(stcb, &desc, net, cp->ch.chunk_flags)) { |
|
4447 SCTP_STAT_INCR(sctps_pdrppdbrk); |
|
4448 break; |
|
4449 } |
|
4450 if (SCTP_SIZE32(at) > chlen) { |
|
4451 break; |
|
4452 } |
|
4453 chlen -= SCTP_SIZE32(at); |
|
4454 if (chlen < sizeof(struct sctp_chunkhdr)) { |
|
4455 /* done, none left */ |
|
4456 break; |
|
4457 } |
|
4458 ch = (struct sctp_chunkhdr *)((caddr_t)ch + SCTP_SIZE32(at)); |
|
4459 } |
|
4460 /* Now update any rwnd --- possibly */ |
|
4461 if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX) == 0) { |
|
4462 /* From a peer, we get a rwnd report */ |
|
4463 uint32_t a_rwnd; |
|
4464 |
|
4465 SCTP_STAT_INCR(sctps_pdrpfehos); |
|
4466 |
|
4467 bottle_bw = ntohl(cp->bottle_bw); |
|
4468 on_queue = ntohl(cp->current_onq); |
|
4469 if (bottle_bw && on_queue) { |
|
4470 /* a rwnd report is in here */ |
|
4471 if (bottle_bw > on_queue) |
|
4472 a_rwnd = bottle_bw - on_queue; |
|
4473 else |
|
4474 a_rwnd = 0; |
|
4475 |
|
4476 if (a_rwnd == 0) |
|
4477 stcb->asoc.peers_rwnd = 0; |
|
4478 else { |
|
4479 if (a_rwnd > stcb->asoc.total_flight) { |
|
4480 stcb->asoc.peers_rwnd = |
|
4481 a_rwnd - stcb->asoc.total_flight; |
|
4482 } else { |
|
4483 stcb->asoc.peers_rwnd = 0; |
|
4484 } |
|
4485 if (stcb->asoc.peers_rwnd < |
|
4486 stcb->sctp_ep->sctp_ep.sctp_sws_sender) { |
|
4487 /* SWS sender side engages */ |
|
4488 stcb->asoc.peers_rwnd = 0; |
|
4489 } |
|
4490 } |
|
4491 } |
|
4492 } else { |
|
4493 SCTP_STAT_INCR(sctps_pdrpfmbox); |
|
4494 } |
|
4495 |
|
4496 /* now middle boxes in sat networks get a cwnd bump */ |
|
4497 if ((cp->ch.chunk_flags & SCTP_FROM_MIDDLE_BOX) && |
|
4498 (stcb->asoc.sat_t3_loss_recovery == 0) && |
|
4499 (stcb->asoc.sat_network)) { |
|
4500 /* |
|
4501 * This is debateable but for sat networks it makes sense |
|
4502 * Note if a T3 timer has went off, we will prohibit any |
|
4503 * changes to cwnd until we exit the t3 loss recovery. |
|
4504 */ |
|
4505 stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped(stcb, |
|
4506 net, cp, &bottle_bw, &on_queue); |
|
4507 } |
|
4508 } |
|
4509 |
|
4510 /* |
|
4511 * handles all control chunks in a packet inputs: - m: mbuf chain, assumed to |
|
4512 * still contain IP/SCTP header - stcb: is the tcb found for this packet - |
|
4513 * offset: offset into the mbuf chain to first chunkhdr - length: is the |
|
4514 * length of the complete packet outputs: - length: modified to remaining |
|
4515 * length after control processing - netp: modified to new sctp_nets after |
|
4516 * cookie-echo processing - return NULL to discard the packet (ie. no asoc, |
|
4517 * bad packet,...) otherwise return the tcb for this packet |
|
4518 */ |
|
4519 #if !defined(__Panda__) |
|
4520 #ifdef __GNUC__ |
|
4521 __attribute__ ((noinline)) |
|
4522 #endif |
|
4523 #endif |
|
4524 static struct sctp_tcb * |
|
4525 sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, |
|
4526 struct sockaddr *src, struct sockaddr *dst, |
|
4527 struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb *inp, |
|
4528 struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen, |
|
4529 #if defined(__FreeBSD__) |
|
4530 uint8_t use_mflowid, uint32_t mflowid, |
|
4531 #endif |
|
4532 uint32_t vrf_id, uint16_t port) |
|
4533 { |
|
4534 struct sctp_association *asoc; |
|
4535 uint32_t vtag_in; |
|
4536 int num_chunks = 0; /* number of control chunks processed */ |
|
4537 uint32_t chk_length; |
|
4538 int ret; |
|
4539 int abort_no_unlock = 0; |
|
4540 int ecne_seen = 0; |
|
4541 /* |
|
4542 * How big should this be, and should it be alloc'd? Lets try the |
|
4543 * d-mtu-ceiling for now (2k) and that should hopefully work ... |
|
4544 * until we get into jumbo grams and such.. |
|
4545 */ |
|
4546 uint8_t chunk_buf[SCTP_CHUNK_BUFFER_SIZE]; |
|
4547 struct sctp_tcb *locked_tcb = stcb; |
|
4548 int got_auth = 0; |
|
4549 uint32_t auth_offset = 0, auth_len = 0; |
|
4550 int auth_skipped = 0; |
|
4551 int asconf_cnt = 0; |
|
4552 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
4553 struct socket *so; |
|
4554 #endif |
|
4555 |
|
4556 SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_control: iphlen=%u, offset=%u, length=%u stcb:%p\n", |
|
4557 iphlen, *offset, length, (void *)stcb); |
|
4558 |
|
4559 /* validate chunk header length... */ |
|
4560 if (ntohs(ch->chunk_length) < sizeof(*ch)) { |
|
4561 SCTPDBG(SCTP_DEBUG_INPUT1, "Invalid header length %d\n", |
|
4562 ntohs(ch->chunk_length)); |
|
4563 if (locked_tcb) { |
|
4564 SCTP_TCB_UNLOCK(locked_tcb); |
|
4565 } |
|
4566 return (NULL); |
|
4567 } |
|
4568 /* |
|
4569 * validate the verification tag |
|
4570 */ |
|
4571 vtag_in = ntohl(sh->v_tag); |
|
4572 |
|
4573 if (locked_tcb) { |
|
4574 SCTP_TCB_LOCK_ASSERT(locked_tcb); |
|
4575 } |
|
4576 if (ch->chunk_type == SCTP_INITIATION) { |
|
4577 SCTPDBG(SCTP_DEBUG_INPUT1, "Its an INIT of len:%d vtag:%x\n", |
|
4578 ntohs(ch->chunk_length), vtag_in); |
|
4579 if (vtag_in != 0) { |
|
4580 /* protocol error- silently discard... */ |
|
4581 SCTP_STAT_INCR(sctps_badvtag); |
|
4582 if (locked_tcb) { |
|
4583 SCTP_TCB_UNLOCK(locked_tcb); |
|
4584 } |
|
4585 return (NULL); |
|
4586 } |
|
4587 } else if (ch->chunk_type != SCTP_COOKIE_ECHO) { |
|
4588 /* |
|
4589 * If there is no stcb, skip the AUTH chunk and process |
|
4590 * later after a stcb is found (to validate the lookup was |
|
4591 * valid. |
|
4592 */ |
|
4593 if ((ch->chunk_type == SCTP_AUTHENTICATION) && |
|
4594 (stcb == NULL) && |
|
4595 !SCTP_BASE_SYSCTL(sctp_auth_disable)) { |
|
4596 /* save this chunk for later processing */ |
|
4597 auth_skipped = 1; |
|
4598 auth_offset = *offset; |
|
4599 auth_len = ntohs(ch->chunk_length); |
|
4600 |
|
4601 /* (temporarily) move past this chunk */ |
|
4602 *offset += SCTP_SIZE32(auth_len); |
|
4603 if (*offset >= length) { |
|
4604 /* no more data left in the mbuf chain */ |
|
4605 *offset = length; |
|
4606 if (locked_tcb) { |
|
4607 SCTP_TCB_UNLOCK(locked_tcb); |
|
4608 } |
|
4609 return (NULL); |
|
4610 } |
|
4611 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, |
|
4612 sizeof(struct sctp_chunkhdr), chunk_buf); |
|
4613 } |
|
4614 if (ch == NULL) { |
|
4615 /* Help */ |
|
4616 *offset = length; |
|
4617 if (locked_tcb) { |
|
4618 SCTP_TCB_UNLOCK(locked_tcb); |
|
4619 } |
|
4620 return (NULL); |
|
4621 } |
|
4622 if (ch->chunk_type == SCTP_COOKIE_ECHO) { |
|
4623 goto process_control_chunks; |
|
4624 } |
|
4625 /* |
|
4626 * first check if it's an ASCONF with an unknown src addr we |
|
4627 * need to look inside to find the association |
|
4628 */ |
|
4629 if (ch->chunk_type == SCTP_ASCONF && stcb == NULL) { |
|
4630 struct sctp_chunkhdr *asconf_ch = ch; |
|
4631 uint32_t asconf_offset = 0, asconf_len = 0; |
|
4632 |
|
4633 /* inp's refcount may be reduced */ |
|
4634 SCTP_INP_INCR_REF(inp); |
|
4635 |
|
4636 asconf_offset = *offset; |
|
4637 do { |
|
4638 asconf_len = ntohs(asconf_ch->chunk_length); |
|
4639 if (asconf_len < sizeof(struct sctp_asconf_paramhdr)) |
|
4640 break; |
|
4641 stcb = sctp_findassociation_ep_asconf(m, |
|
4642 *offset, |
|
4643 dst, |
|
4644 sh, &inp, netp, vrf_id); |
|
4645 if (stcb != NULL) |
|
4646 break; |
|
4647 asconf_offset += SCTP_SIZE32(asconf_len); |
|
4648 asconf_ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, asconf_offset, |
|
4649 sizeof(struct sctp_chunkhdr), chunk_buf); |
|
4650 } while (asconf_ch != NULL && asconf_ch->chunk_type == SCTP_ASCONF); |
|
4651 if (stcb == NULL) { |
|
4652 /* |
|
4653 * reduce inp's refcount if not reduced in |
|
4654 * sctp_findassociation_ep_asconf(). |
|
4655 */ |
|
4656 SCTP_INP_DECR_REF(inp); |
|
4657 } else { |
|
4658 locked_tcb = stcb; |
|
4659 } |
|
4660 |
|
4661 /* now go back and verify any auth chunk to be sure */ |
|
4662 if (auth_skipped && (stcb != NULL)) { |
|
4663 struct sctp_auth_chunk *auth; |
|
4664 |
|
4665 auth = (struct sctp_auth_chunk *) |
|
4666 sctp_m_getptr(m, auth_offset, |
|
4667 auth_len, chunk_buf); |
|
4668 got_auth = 1; |
|
4669 auth_skipped = 0; |
|
4670 if ((auth == NULL) || sctp_handle_auth(stcb, auth, m, |
|
4671 auth_offset)) { |
|
4672 /* auth HMAC failed so dump it */ |
|
4673 *offset = length; |
|
4674 if (locked_tcb) { |
|
4675 SCTP_TCB_UNLOCK(locked_tcb); |
|
4676 } |
|
4677 return (NULL); |
|
4678 } else { |
|
4679 /* remaining chunks are HMAC checked */ |
|
4680 stcb->asoc.authenticated = 1; |
|
4681 } |
|
4682 } |
|
4683 } |
|
4684 if (stcb == NULL) { |
|
4685 /* no association, so it's out of the blue... */ |
|
4686 sctp_handle_ootb(m, iphlen, *offset, src, dst, sh, inp, |
|
4687 #if defined(__FreeBSD__) |
|
4688 use_mflowid, mflowid, |
|
4689 #endif |
|
4690 vrf_id, port); |
|
4691 *offset = length; |
|
4692 if (locked_tcb) { |
|
4693 SCTP_TCB_UNLOCK(locked_tcb); |
|
4694 } |
|
4695 return (NULL); |
|
4696 } |
|
4697 asoc = &stcb->asoc; |
|
4698 /* ABORT and SHUTDOWN can use either v_tag... */ |
|
4699 if ((ch->chunk_type == SCTP_ABORT_ASSOCIATION) || |
|
4700 (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) || |
|
4701 (ch->chunk_type == SCTP_PACKET_DROPPED)) { |
|
4702 /* Take the T-bit always into account. */ |
|
4703 if ((((ch->chunk_flags & SCTP_HAD_NO_TCB) == 0) && |
|
4704 (vtag_in == asoc->my_vtag)) || |
|
4705 (((ch->chunk_flags & SCTP_HAD_NO_TCB) == SCTP_HAD_NO_TCB) && |
|
4706 (vtag_in == asoc->peer_vtag))) { |
|
4707 /* this is valid */ |
|
4708 } else { |
|
4709 /* drop this packet... */ |
|
4710 SCTP_STAT_INCR(sctps_badvtag); |
|
4711 if (locked_tcb) { |
|
4712 SCTP_TCB_UNLOCK(locked_tcb); |
|
4713 } |
|
4714 return (NULL); |
|
4715 } |
|
4716 } else if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { |
|
4717 if (vtag_in != asoc->my_vtag) { |
|
4718 /* |
|
4719 * this could be a stale SHUTDOWN-ACK or the |
|
4720 * peer never got the SHUTDOWN-COMPLETE and |
|
4721 * is still hung; we have started a new asoc |
|
4722 * but it won't complete until the shutdown |
|
4723 * is completed |
|
4724 */ |
|
4725 if (locked_tcb) { |
|
4726 SCTP_TCB_UNLOCK(locked_tcb); |
|
4727 } |
|
4728 sctp_handle_ootb(m, iphlen, *offset, src, dst, |
|
4729 sh, inp, |
|
4730 #if defined(__FreeBSD__) |
|
4731 use_mflowid, mflowid, |
|
4732 #endif |
|
4733 vrf_id, port); |
|
4734 return (NULL); |
|
4735 } |
|
4736 } else { |
|
4737 /* for all other chunks, vtag must match */ |
|
4738 if (vtag_in != asoc->my_vtag) { |
|
4739 /* invalid vtag... */ |
|
4740 SCTPDBG(SCTP_DEBUG_INPUT3, |
|
4741 "invalid vtag: %xh, expect %xh\n", |
|
4742 vtag_in, asoc->my_vtag); |
|
4743 SCTP_STAT_INCR(sctps_badvtag); |
|
4744 if (locked_tcb) { |
|
4745 SCTP_TCB_UNLOCK(locked_tcb); |
|
4746 } |
|
4747 *offset = length; |
|
4748 return (NULL); |
|
4749 } |
|
4750 } |
|
4751 } /* end if !SCTP_COOKIE_ECHO */ |
|
4752 /* |
|
4753 * process all control chunks... |
|
4754 */ |
|
4755 if (((ch->chunk_type == SCTP_SELECTIVE_ACK) || |
|
4756 (ch->chunk_type == SCTP_NR_SELECTIVE_ACK) || |
|
4757 (ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) && |
|
4758 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { |
|
4759 /* implied cookie-ack.. we must have lost the ack */ |
|
4760 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
4761 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
4762 stcb->asoc.overall_error_count, |
|
4763 0, |
|
4764 SCTP_FROM_SCTP_INPUT, |
|
4765 __LINE__); |
|
4766 } |
|
4767 stcb->asoc.overall_error_count = 0; |
|
4768 sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, |
|
4769 *netp); |
|
4770 } |
|
4771 |
|
4772 process_control_chunks: |
|
4773 while (IS_SCTP_CONTROL(ch)) { |
|
4774 /* validate chunk length */ |
|
4775 chk_length = ntohs(ch->chunk_length); |
|
4776 SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_process_control: processing a chunk type=%u, len=%u\n", |
|
4777 ch->chunk_type, chk_length); |
|
4778 SCTP_LTRACE_CHK(inp, stcb, ch->chunk_type, chk_length); |
|
4779 if (chk_length < sizeof(*ch) || |
|
4780 (*offset + (int)chk_length) > length) { |
|
4781 *offset = length; |
|
4782 if (locked_tcb) { |
|
4783 SCTP_TCB_UNLOCK(locked_tcb); |
|
4784 } |
|
4785 return (NULL); |
|
4786 } |
|
4787 SCTP_STAT_INCR_COUNTER64(sctps_incontrolchunks); |
|
4788 /* |
|
4789 * INIT-ACK only gets the init ack "header" portion only |
|
4790 * because we don't have to process the peer's COOKIE. All |
|
4791 * others get a complete chunk. |
|
4792 */ |
|
4793 if ((ch->chunk_type == SCTP_INITIATION_ACK) || |
|
4794 (ch->chunk_type == SCTP_INITIATION)) { |
|
4795 /* get an init-ack chunk */ |
|
4796 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, |
|
4797 sizeof(struct sctp_init_ack_chunk), chunk_buf); |
|
4798 if (ch == NULL) { |
|
4799 *offset = length; |
|
4800 if (locked_tcb) { |
|
4801 SCTP_TCB_UNLOCK(locked_tcb); |
|
4802 } |
|
4803 return (NULL); |
|
4804 } |
|
4805 } else { |
|
4806 /* For cookies and all other chunks. */ |
|
4807 if (chk_length > sizeof(chunk_buf)) { |
|
4808 /* |
|
4809 * use just the size of the chunk buffer |
|
4810 * so the front part of our chunks fit in |
|
4811 * contiguous space up to the chunk buffer |
|
4812 * size (508 bytes). |
|
4813 * For chunks that need to get more than that |
|
4814 * they must use the sctp_m_getptr() function |
|
4815 * or other means (e.g. know how to parse mbuf |
|
4816 * chains). Cookies do this already. |
|
4817 */ |
|
4818 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, |
|
4819 (sizeof(chunk_buf) - 4), |
|
4820 chunk_buf); |
|
4821 if (ch == NULL) { |
|
4822 *offset = length; |
|
4823 if (locked_tcb) { |
|
4824 SCTP_TCB_UNLOCK(locked_tcb); |
|
4825 } |
|
4826 return (NULL); |
|
4827 } |
|
4828 } else { |
|
4829 /* We can fit it all */ |
|
4830 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, |
|
4831 chk_length, chunk_buf); |
|
4832 if (ch == NULL) { |
|
4833 SCTP_PRINTF("sctp_process_control: Can't get the all data....\n"); |
|
4834 *offset = length; |
|
4835 if (locked_tcb) { |
|
4836 SCTP_TCB_UNLOCK(locked_tcb); |
|
4837 } |
|
4838 return (NULL); |
|
4839 } |
|
4840 } |
|
4841 } |
|
4842 num_chunks++; |
|
4843 /* Save off the last place we got a control from */ |
|
4844 if (stcb != NULL) { |
|
4845 if (((netp != NULL) && (*netp != NULL)) || (ch->chunk_type == SCTP_ASCONF)) { |
|
4846 /* |
|
4847 * allow last_control to be NULL if |
|
4848 * ASCONF... ASCONF processing will find the |
|
4849 * right net later |
|
4850 */ |
|
4851 if ((netp != NULL) && (*netp != NULL)) |
|
4852 stcb->asoc.last_control_chunk_from = *netp; |
|
4853 } |
|
4854 } |
|
4855 #ifdef SCTP_AUDITING_ENABLED |
|
4856 sctp_audit_log(0xB0, ch->chunk_type); |
|
4857 #endif |
|
4858 |
|
4859 /* check to see if this chunk required auth, but isn't */ |
|
4860 if ((stcb != NULL) && |
|
4861 !SCTP_BASE_SYSCTL(sctp_auth_disable) && |
|
4862 sctp_auth_is_required_chunk(ch->chunk_type, stcb->asoc.local_auth_chunks) && |
|
4863 !stcb->asoc.authenticated) { |
|
4864 /* "silently" ignore */ |
|
4865 SCTP_STAT_INCR(sctps_recvauthmissing); |
|
4866 goto next_chunk; |
|
4867 } |
|
4868 switch (ch->chunk_type) { |
|
4869 case SCTP_INITIATION: |
|
4870 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT\n"); |
|
4871 /* The INIT chunk must be the only chunk. */ |
|
4872 if ((num_chunks > 1) || |
|
4873 (length - *offset > (int)SCTP_SIZE32(chk_length))) { |
|
4874 sctp_abort_association(inp, stcb, m, iphlen, |
|
4875 src, dst, sh, NULL, |
|
4876 #if defined(__FreeBSD__) |
|
4877 use_mflowid, mflowid, |
|
4878 #endif |
|
4879 vrf_id, port); |
|
4880 *offset = length; |
|
4881 return (NULL); |
|
4882 } |
|
4883 /* Honor our resource limit. */ |
|
4884 if (chk_length > SCTP_LARGEST_INIT_ACCEPTED) { |
|
4885 struct mbuf *op_err; |
|
4886 |
|
4887 op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); |
|
4888 sctp_abort_association(inp, stcb, m, iphlen, |
|
4889 src, dst, sh, op_err, |
|
4890 #if defined(__FreeBSD__) |
|
4891 use_mflowid, mflowid, |
|
4892 #endif |
|
4893 vrf_id, port); |
|
4894 *offset = length; |
|
4895 return (NULL); |
|
4896 } |
|
4897 sctp_handle_init(m, iphlen, *offset, src, dst, sh, |
|
4898 (struct sctp_init_chunk *)ch, inp, |
|
4899 stcb, &abort_no_unlock, |
|
4900 #if defined(__FreeBSD__) |
|
4901 use_mflowid, mflowid, |
|
4902 #endif |
|
4903 vrf_id, port); |
|
4904 *offset = length; |
|
4905 if ((!abort_no_unlock) && (locked_tcb)) { |
|
4906 SCTP_TCB_UNLOCK(locked_tcb); |
|
4907 } |
|
4908 return (NULL); |
|
4909 break; |
|
4910 case SCTP_PAD_CHUNK: |
|
4911 break; |
|
4912 case SCTP_INITIATION_ACK: |
|
4913 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_INIT-ACK\n"); |
|
4914 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { |
|
4915 /* We are not interested anymore */ |
|
4916 if ((stcb) && (stcb->asoc.total_output_queue_size)) { |
|
4917 ; |
|
4918 } else { |
|
4919 if (locked_tcb != stcb) { |
|
4920 /* Very unlikely */ |
|
4921 SCTP_TCB_UNLOCK(locked_tcb); |
|
4922 } |
|
4923 *offset = length; |
|
4924 if (stcb) { |
|
4925 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
4926 so = SCTP_INP_SO(inp); |
|
4927 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
4928 SCTP_TCB_UNLOCK(stcb); |
|
4929 SCTP_SOCKET_LOCK(so, 1); |
|
4930 SCTP_TCB_LOCK(stcb); |
|
4931 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
4932 #endif |
|
4933 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_27); |
|
4934 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
4935 SCTP_SOCKET_UNLOCK(so, 1); |
|
4936 #endif |
|
4937 } |
|
4938 return (NULL); |
|
4939 } |
|
4940 } |
|
4941 /* The INIT-ACK chunk must be the only chunk. */ |
|
4942 if ((num_chunks > 1) || |
|
4943 (length - *offset > (int)SCTP_SIZE32(chk_length))) { |
|
4944 *offset = length; |
|
4945 if (locked_tcb) { |
|
4946 SCTP_TCB_UNLOCK(locked_tcb); |
|
4947 } |
|
4948 return (NULL); |
|
4949 } |
|
4950 if ((netp) && (*netp)) { |
|
4951 ret = sctp_handle_init_ack(m, iphlen, *offset, |
|
4952 src, dst, sh, |
|
4953 (struct sctp_init_ack_chunk *)ch, |
|
4954 stcb, *netp, |
|
4955 &abort_no_unlock, |
|
4956 #if defined(__FreeBSD__) |
|
4957 use_mflowid, mflowid, |
|
4958 #endif |
|
4959 vrf_id); |
|
4960 } else { |
|
4961 ret = -1; |
|
4962 } |
|
4963 *offset = length; |
|
4964 if (abort_no_unlock) { |
|
4965 return (NULL); |
|
4966 } |
|
4967 /* |
|
4968 * Special case, I must call the output routine to |
|
4969 * get the cookie echoed |
|
4970 */ |
|
4971 if ((stcb != NULL) && (ret == 0)) { |
|
4972 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); |
|
4973 } |
|
4974 if (locked_tcb) { |
|
4975 SCTP_TCB_UNLOCK(locked_tcb); |
|
4976 } |
|
4977 return (NULL); |
|
4978 break; |
|
4979 case SCTP_SELECTIVE_ACK: |
|
4980 { |
|
4981 struct sctp_sack_chunk *sack; |
|
4982 int abort_now = 0; |
|
4983 uint32_t a_rwnd, cum_ack; |
|
4984 uint16_t num_seg, num_dup; |
|
4985 uint8_t flags; |
|
4986 int offset_seg, offset_dup; |
|
4987 |
|
4988 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK\n"); |
|
4989 SCTP_STAT_INCR(sctps_recvsacks); |
|
4990 if (stcb == NULL) { |
|
4991 SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing SACK chunk\n"); |
|
4992 break; |
|
4993 } |
|
4994 if (chk_length < sizeof(struct sctp_sack_chunk)) { |
|
4995 SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on SACK chunk, too small\n"); |
|
4996 break; |
|
4997 } |
|
4998 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) { |
|
4999 /*- |
|
5000 * If we have sent a shutdown-ack, we will pay no |
|
5001 * attention to a sack sent in to us since |
|
5002 * we don't care anymore. |
|
5003 */ |
|
5004 break; |
|
5005 } |
|
5006 sack = (struct sctp_sack_chunk *)ch; |
|
5007 flags = ch->chunk_flags; |
|
5008 cum_ack = ntohl(sack->sack.cum_tsn_ack); |
|
5009 num_seg = ntohs(sack->sack.num_gap_ack_blks); |
|
5010 num_dup = ntohs(sack->sack.num_dup_tsns); |
|
5011 a_rwnd = (uint32_t) ntohl(sack->sack.a_rwnd); |
|
5012 if (sizeof(struct sctp_sack_chunk) + |
|
5013 num_seg * sizeof(struct sctp_gap_ack_block) + |
|
5014 num_dup * sizeof(uint32_t) != chk_length) { |
|
5015 SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size of SACK chunk\n"); |
|
5016 break; |
|
5017 } |
|
5018 offset_seg = *offset + sizeof(struct sctp_sack_chunk); |
|
5019 offset_dup = offset_seg + num_seg * sizeof(struct sctp_gap_ack_block); |
|
5020 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK process cum_ack:%x num_seg:%d a_rwnd:%d\n", |
|
5021 cum_ack, num_seg, a_rwnd); |
|
5022 stcb->asoc.seen_a_sack_this_pkt = 1; |
|
5023 if ((stcb->asoc.pr_sctp_cnt == 0) && |
|
5024 (num_seg == 0) && |
|
5025 SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) && |
|
5026 (stcb->asoc.saw_sack_with_frags == 0) && |
|
5027 (stcb->asoc.saw_sack_with_nr_frags == 0) && |
|
5028 (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) |
|
5029 ) { |
|
5030 /* We have a SIMPLE sack having no prior segments and |
|
5031 * data on sent queue to be acked.. Use the faster |
|
5032 * path sack processing. We also allow window update |
|
5033 * sacks with no missing segments to go this way too. |
|
5034 */ |
|
5035 sctp_express_handle_sack(stcb, cum_ack, a_rwnd, &abort_now, ecne_seen); |
|
5036 } else { |
|
5037 if (netp && *netp) |
|
5038 sctp_handle_sack(m, offset_seg, offset_dup, stcb, |
|
5039 num_seg, 0, num_dup, &abort_now, flags, |
|
5040 cum_ack, a_rwnd, ecne_seen); |
|
5041 } |
|
5042 if (abort_now) { |
|
5043 /* ABORT signal from sack processing */ |
|
5044 *offset = length; |
|
5045 return (NULL); |
|
5046 } |
|
5047 if (TAILQ_EMPTY(&stcb->asoc.send_queue) && |
|
5048 TAILQ_EMPTY(&stcb->asoc.sent_queue) && |
|
5049 (stcb->asoc.stream_queue_cnt == 0)) { |
|
5050 sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
5051 } |
|
5052 } |
|
5053 break; |
|
5054 /* EY - nr_sack: If the received chunk is an nr_sack chunk */ |
|
5055 case SCTP_NR_SELECTIVE_ACK: |
|
5056 { |
|
5057 struct sctp_nr_sack_chunk *nr_sack; |
|
5058 int abort_now = 0; |
|
5059 uint32_t a_rwnd, cum_ack; |
|
5060 uint16_t num_seg, num_nr_seg, num_dup; |
|
5061 uint8_t flags; |
|
5062 int offset_seg, offset_dup; |
|
5063 |
|
5064 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK\n"); |
|
5065 SCTP_STAT_INCR(sctps_recvsacks); |
|
5066 if (stcb == NULL) { |
|
5067 SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing NR-SACK chunk\n"); |
|
5068 break; |
|
5069 } |
|
5070 if ((stcb->asoc.sctp_nr_sack_on_off == 0) || |
|
5071 (stcb->asoc.peer_supports_nr_sack == 0)) { |
|
5072 goto unknown_chunk; |
|
5073 } |
|
5074 if (chk_length < sizeof(struct sctp_nr_sack_chunk)) { |
|
5075 SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on NR-SACK chunk, too small\n"); |
|
5076 break; |
|
5077 } |
|
5078 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) { |
|
5079 /*- |
|
5080 * If we have sent a shutdown-ack, we will pay no |
|
5081 * attention to a sack sent in to us since |
|
5082 * we don't care anymore. |
|
5083 */ |
|
5084 break; |
|
5085 } |
|
5086 nr_sack = (struct sctp_nr_sack_chunk *)ch; |
|
5087 flags = ch->chunk_flags; |
|
5088 cum_ack = ntohl(nr_sack->nr_sack.cum_tsn_ack); |
|
5089 num_seg = ntohs(nr_sack->nr_sack.num_gap_ack_blks); |
|
5090 num_nr_seg = ntohs(nr_sack->nr_sack.num_nr_gap_ack_blks); |
|
5091 num_dup = ntohs(nr_sack->nr_sack.num_dup_tsns); |
|
5092 a_rwnd = (uint32_t) ntohl(nr_sack->nr_sack.a_rwnd); |
|
5093 if (sizeof(struct sctp_nr_sack_chunk) + |
|
5094 (num_seg + num_nr_seg) * sizeof(struct sctp_gap_ack_block) + |
|
5095 num_dup * sizeof(uint32_t) != chk_length) { |
|
5096 SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size of NR_SACK chunk\n"); |
|
5097 break; |
|
5098 } |
|
5099 offset_seg = *offset + sizeof(struct sctp_nr_sack_chunk); |
|
5100 offset_dup = offset_seg + num_seg * sizeof(struct sctp_gap_ack_block); |
|
5101 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK process cum_ack:%x num_seg:%d a_rwnd:%d\n", |
|
5102 cum_ack, num_seg, a_rwnd); |
|
5103 stcb->asoc.seen_a_sack_this_pkt = 1; |
|
5104 if ((stcb->asoc.pr_sctp_cnt == 0) && |
|
5105 (num_seg == 0) && (num_nr_seg == 0) && |
|
5106 SCTP_TSN_GE(cum_ack, stcb->asoc.last_acked_seq) && |
|
5107 (stcb->asoc.saw_sack_with_frags == 0) && |
|
5108 (stcb->asoc.saw_sack_with_nr_frags == 0) && |
|
5109 (!TAILQ_EMPTY(&stcb->asoc.sent_queue))) { |
|
5110 /* |
|
5111 * We have a SIMPLE sack having no |
|
5112 * prior segments and data on sent |
|
5113 * queue to be acked. Use the |
|
5114 * faster path sack processing. We |
|
5115 * also allow window update sacks |
|
5116 * with no missing segments to go |
|
5117 * this way too. |
|
5118 */ |
|
5119 sctp_express_handle_sack(stcb, cum_ack, a_rwnd, |
|
5120 &abort_now, ecne_seen); |
|
5121 } else { |
|
5122 if (netp && *netp) |
|
5123 sctp_handle_sack(m, offset_seg, offset_dup, stcb, |
|
5124 num_seg, num_nr_seg, num_dup, &abort_now, flags, |
|
5125 cum_ack, a_rwnd, ecne_seen); |
|
5126 } |
|
5127 if (abort_now) { |
|
5128 /* ABORT signal from sack processing */ |
|
5129 *offset = length; |
|
5130 return (NULL); |
|
5131 } |
|
5132 if (TAILQ_EMPTY(&stcb->asoc.send_queue) && |
|
5133 TAILQ_EMPTY(&stcb->asoc.sent_queue) && |
|
5134 (stcb->asoc.stream_queue_cnt == 0)) { |
|
5135 sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
5136 } |
|
5137 } |
|
5138 break; |
|
5139 |
|
5140 case SCTP_HEARTBEAT_REQUEST: |
|
5141 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT\n"); |
|
5142 if ((stcb) && netp && *netp) { |
|
5143 SCTP_STAT_INCR(sctps_recvheartbeat); |
|
5144 sctp_send_heartbeat_ack(stcb, m, *offset, |
|
5145 chk_length, *netp); |
|
5146 |
|
5147 /* He's alive so give him credit */ |
|
5148 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5149 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5150 stcb->asoc.overall_error_count, |
|
5151 0, |
|
5152 SCTP_FROM_SCTP_INPUT, |
|
5153 __LINE__); |
|
5154 } |
|
5155 stcb->asoc.overall_error_count = 0; |
|
5156 } |
|
5157 break; |
|
5158 case SCTP_HEARTBEAT_ACK: |
|
5159 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT-ACK\n"); |
|
5160 if ((stcb == NULL) || (chk_length != sizeof(struct sctp_heartbeat_chunk))) { |
|
5161 /* Its not ours */ |
|
5162 *offset = length; |
|
5163 if (locked_tcb) { |
|
5164 SCTP_TCB_UNLOCK(locked_tcb); |
|
5165 } |
|
5166 return (NULL); |
|
5167 } |
|
5168 /* He's alive so give him credit */ |
|
5169 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5170 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5171 stcb->asoc.overall_error_count, |
|
5172 0, |
|
5173 SCTP_FROM_SCTP_INPUT, |
|
5174 __LINE__); |
|
5175 } |
|
5176 stcb->asoc.overall_error_count = 0; |
|
5177 SCTP_STAT_INCR(sctps_recvheartbeatack); |
|
5178 if (netp && *netp) |
|
5179 sctp_handle_heartbeat_ack((struct sctp_heartbeat_chunk *)ch, |
|
5180 stcb, *netp); |
|
5181 break; |
|
5182 case SCTP_ABORT_ASSOCIATION: |
|
5183 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ABORT, stcb %p\n", |
|
5184 (void *)stcb); |
|
5185 if ((stcb) && netp && *netp) |
|
5186 sctp_handle_abort((struct sctp_abort_chunk *)ch, |
|
5187 stcb, *netp); |
|
5188 *offset = length; |
|
5189 return (NULL); |
|
5190 break; |
|
5191 case SCTP_SHUTDOWN: |
|
5192 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN, stcb %p\n", |
|
5193 (void *)stcb); |
|
5194 if ((stcb == NULL) || (chk_length != sizeof(struct sctp_shutdown_chunk))) { |
|
5195 *offset = length; |
|
5196 if (locked_tcb) { |
|
5197 SCTP_TCB_UNLOCK(locked_tcb); |
|
5198 } |
|
5199 return (NULL); |
|
5200 } |
|
5201 if (netp && *netp) { |
|
5202 int abort_flag = 0; |
|
5203 |
|
5204 sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch, |
|
5205 stcb, *netp, &abort_flag); |
|
5206 if (abort_flag) { |
|
5207 *offset = length; |
|
5208 return (NULL); |
|
5209 } |
|
5210 } |
|
5211 break; |
|
5212 case SCTP_SHUTDOWN_ACK: |
|
5213 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN-ACK, stcb %p\n", (void *)stcb); |
|
5214 if ((stcb) && (netp) && (*netp)) |
|
5215 sctp_handle_shutdown_ack((struct sctp_shutdown_ack_chunk *)ch, stcb, *netp); |
|
5216 *offset = length; |
|
5217 return (NULL); |
|
5218 break; |
|
5219 |
|
5220 case SCTP_OPERATION_ERROR: |
|
5221 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP-ERR\n"); |
|
5222 if ((stcb) && netp && *netp && sctp_handle_error(ch, stcb, *netp) < 0) { |
|
5223 *offset = length; |
|
5224 return (NULL); |
|
5225 } |
|
5226 break; |
|
5227 case SCTP_COOKIE_ECHO: |
|
5228 SCTPDBG(SCTP_DEBUG_INPUT3, |
|
5229 "SCTP_COOKIE-ECHO, stcb %p\n", (void *)stcb); |
|
5230 if ((stcb) && (stcb->asoc.total_output_queue_size)) { |
|
5231 ; |
|
5232 } else { |
|
5233 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { |
|
5234 /* We are not interested anymore */ |
|
5235 abend: |
|
5236 if (stcb) { |
|
5237 SCTP_TCB_UNLOCK(stcb); |
|
5238 } |
|
5239 *offset = length; |
|
5240 return (NULL); |
|
5241 } |
|
5242 } |
|
5243 /* |
|
5244 * First are we accepting? We do this again here |
|
5245 * since it is possible that a previous endpoint WAS |
|
5246 * listening responded to a INIT-ACK and then |
|
5247 * closed. We opened and bound.. and are now no |
|
5248 * longer listening. |
|
5249 */ |
|
5250 |
|
5251 if ((stcb == NULL) && (inp->sctp_socket->so_qlen >= inp->sctp_socket->so_qlimit)) { |
|
5252 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
5253 (SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit))) { |
|
5254 struct mbuf *op_err; |
|
5255 |
|
5256 op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); |
|
5257 sctp_abort_association(inp, stcb, m, iphlen, |
|
5258 src, dst, sh, op_err, |
|
5259 #if defined(__FreeBSD__) |
|
5260 use_mflowid, mflowid, |
|
5261 #endif |
|
5262 vrf_id, port); |
|
5263 } |
|
5264 *offset = length; |
|
5265 return (NULL); |
|
5266 } else { |
|
5267 struct mbuf *ret_buf; |
|
5268 struct sctp_inpcb *linp; |
|
5269 if (stcb) { |
|
5270 linp = NULL; |
|
5271 } else { |
|
5272 linp = inp; |
|
5273 } |
|
5274 |
|
5275 if (linp) { |
|
5276 SCTP_ASOC_CREATE_LOCK(linp); |
|
5277 if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || |
|
5278 (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { |
|
5279 SCTP_ASOC_CREATE_UNLOCK(linp); |
|
5280 goto abend; |
|
5281 } |
|
5282 } |
|
5283 |
|
5284 if (netp) { |
|
5285 ret_buf = |
|
5286 sctp_handle_cookie_echo(m, iphlen, |
|
5287 *offset, |
|
5288 src, dst, |
|
5289 sh, |
|
5290 (struct sctp_cookie_echo_chunk *)ch, |
|
5291 &inp, &stcb, netp, |
|
5292 auth_skipped, |
|
5293 auth_offset, |
|
5294 auth_len, |
|
5295 &locked_tcb, |
|
5296 #if defined(__FreeBSD__) |
|
5297 use_mflowid, |
|
5298 mflowid, |
|
5299 #endif |
|
5300 vrf_id, |
|
5301 port); |
|
5302 } else { |
|
5303 ret_buf = NULL; |
|
5304 } |
|
5305 if (linp) { |
|
5306 SCTP_ASOC_CREATE_UNLOCK(linp); |
|
5307 } |
|
5308 if (ret_buf == NULL) { |
|
5309 if (locked_tcb) { |
|
5310 SCTP_TCB_UNLOCK(locked_tcb); |
|
5311 } |
|
5312 SCTPDBG(SCTP_DEBUG_INPUT3, |
|
5313 "GAK, null buffer\n"); |
|
5314 *offset = length; |
|
5315 return (NULL); |
|
5316 } |
|
5317 /* if AUTH skipped, see if it verified... */ |
|
5318 if (auth_skipped) { |
|
5319 got_auth = 1; |
|
5320 auth_skipped = 0; |
|
5321 } |
|
5322 if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) { |
|
5323 /* |
|
5324 * Restart the timer if we have |
|
5325 * pending data |
|
5326 */ |
|
5327 struct sctp_tmit_chunk *chk; |
|
5328 |
|
5329 chk = TAILQ_FIRST(&stcb->asoc.sent_queue); |
|
5330 sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo); |
|
5331 } |
|
5332 } |
|
5333 break; |
|
5334 case SCTP_COOKIE_ACK: |
|
5335 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE-ACK, stcb %p\n", (void *)stcb); |
|
5336 if ((stcb == NULL) || chk_length != sizeof(struct sctp_cookie_ack_chunk)) { |
|
5337 if (locked_tcb) { |
|
5338 SCTP_TCB_UNLOCK(locked_tcb); |
|
5339 } |
|
5340 return (NULL); |
|
5341 } |
|
5342 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { |
|
5343 /* We are not interested anymore */ |
|
5344 if ((stcb) && (stcb->asoc.total_output_queue_size)) { |
|
5345 ; |
|
5346 } else if (stcb) { |
|
5347 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
5348 so = SCTP_INP_SO(inp); |
|
5349 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
5350 SCTP_TCB_UNLOCK(stcb); |
|
5351 SCTP_SOCKET_LOCK(so, 1); |
|
5352 SCTP_TCB_LOCK(stcb); |
|
5353 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
5354 #endif |
|
5355 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_27); |
|
5356 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
5357 SCTP_SOCKET_UNLOCK(so, 1); |
|
5358 #endif |
|
5359 *offset = length; |
|
5360 return (NULL); |
|
5361 } |
|
5362 } |
|
5363 /* He's alive so give him credit */ |
|
5364 if ((stcb) && netp && *netp) { |
|
5365 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5366 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5367 stcb->asoc.overall_error_count, |
|
5368 0, |
|
5369 SCTP_FROM_SCTP_INPUT, |
|
5370 __LINE__); |
|
5371 } |
|
5372 stcb->asoc.overall_error_count = 0; |
|
5373 sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch,stcb, *netp); |
|
5374 } |
|
5375 break; |
|
5376 case SCTP_ECN_ECHO: |
|
5377 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN-ECHO\n"); |
|
5378 /* He's alive so give him credit */ |
|
5379 if ((stcb == NULL) || (chk_length != sizeof(struct sctp_ecne_chunk))) { |
|
5380 /* Its not ours */ |
|
5381 if (locked_tcb) { |
|
5382 SCTP_TCB_UNLOCK(locked_tcb); |
|
5383 } |
|
5384 *offset = length; |
|
5385 return (NULL); |
|
5386 } |
|
5387 if (stcb) { |
|
5388 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5389 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5390 stcb->asoc.overall_error_count, |
|
5391 0, |
|
5392 SCTP_FROM_SCTP_INPUT, |
|
5393 __LINE__); |
|
5394 } |
|
5395 stcb->asoc.overall_error_count = 0; |
|
5396 sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, |
|
5397 stcb); |
|
5398 ecne_seen = 1; |
|
5399 } |
|
5400 break; |
|
5401 case SCTP_ECN_CWR: |
|
5402 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN-CWR\n"); |
|
5403 /* He's alive so give him credit */ |
|
5404 if ((stcb == NULL) || (chk_length != sizeof(struct sctp_cwr_chunk))) { |
|
5405 /* Its not ours */ |
|
5406 if (locked_tcb) { |
|
5407 SCTP_TCB_UNLOCK(locked_tcb); |
|
5408 } |
|
5409 *offset = length; |
|
5410 return (NULL); |
|
5411 } |
|
5412 if (stcb) { |
|
5413 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5414 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5415 stcb->asoc.overall_error_count, |
|
5416 0, |
|
5417 SCTP_FROM_SCTP_INPUT, |
|
5418 __LINE__); |
|
5419 } |
|
5420 stcb->asoc.overall_error_count = 0; |
|
5421 sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp); |
|
5422 } |
|
5423 break; |
|
5424 case SCTP_SHUTDOWN_COMPLETE: |
|
5425 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN-COMPLETE, stcb %p\n", (void *)stcb); |
|
5426 /* must be first and only chunk */ |
|
5427 if ((num_chunks > 1) || |
|
5428 (length - *offset > (int)SCTP_SIZE32(chk_length))) { |
|
5429 *offset = length; |
|
5430 if (locked_tcb) { |
|
5431 SCTP_TCB_UNLOCK(locked_tcb); |
|
5432 } |
|
5433 return (NULL); |
|
5434 } |
|
5435 if ((stcb) && netp && *netp) { |
|
5436 sctp_handle_shutdown_complete((struct sctp_shutdown_complete_chunk *)ch, |
|
5437 stcb, *netp); |
|
5438 } |
|
5439 *offset = length; |
|
5440 return (NULL); |
|
5441 break; |
|
5442 case SCTP_ASCONF: |
|
5443 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n"); |
|
5444 /* He's alive so give him credit */ |
|
5445 if (stcb) { |
|
5446 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5447 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5448 stcb->asoc.overall_error_count, |
|
5449 0, |
|
5450 SCTP_FROM_SCTP_INPUT, |
|
5451 __LINE__); |
|
5452 } |
|
5453 stcb->asoc.overall_error_count = 0; |
|
5454 sctp_handle_asconf(m, *offset, src, |
|
5455 (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0); |
|
5456 asconf_cnt++; |
|
5457 } |
|
5458 break; |
|
5459 case SCTP_ASCONF_ACK: |
|
5460 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF-ACK\n"); |
|
5461 if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) { |
|
5462 /* Its not ours */ |
|
5463 if (locked_tcb) { |
|
5464 SCTP_TCB_UNLOCK(locked_tcb); |
|
5465 } |
|
5466 *offset = length; |
|
5467 return (NULL); |
|
5468 } |
|
5469 if ((stcb) && netp && *netp) { |
|
5470 /* He's alive so give him credit */ |
|
5471 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5472 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5473 stcb->asoc.overall_error_count, |
|
5474 0, |
|
5475 SCTP_FROM_SCTP_INPUT, |
|
5476 __LINE__); |
|
5477 } |
|
5478 stcb->asoc.overall_error_count = 0; |
|
5479 sctp_handle_asconf_ack(m, *offset, |
|
5480 (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock); |
|
5481 if (abort_no_unlock) |
|
5482 return (NULL); |
|
5483 } |
|
5484 break; |
|
5485 case SCTP_FORWARD_CUM_TSN: |
|
5486 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD-TSN\n"); |
|
5487 if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) { |
|
5488 /* Its not ours */ |
|
5489 if (locked_tcb) { |
|
5490 SCTP_TCB_UNLOCK(locked_tcb); |
|
5491 } |
|
5492 *offset = length; |
|
5493 return (NULL); |
|
5494 } |
|
5495 |
|
5496 /* He's alive so give him credit */ |
|
5497 if (stcb) { |
|
5498 int abort_flag = 0; |
|
5499 stcb->asoc.overall_error_count = 0; |
|
5500 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5501 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5502 stcb->asoc.overall_error_count, |
|
5503 0, |
|
5504 SCTP_FROM_SCTP_INPUT, |
|
5505 __LINE__); |
|
5506 } |
|
5507 *fwd_tsn_seen = 1; |
|
5508 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { |
|
5509 /* We are not interested anymore */ |
|
5510 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
5511 so = SCTP_INP_SO(inp); |
|
5512 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
5513 SCTP_TCB_UNLOCK(stcb); |
|
5514 SCTP_SOCKET_LOCK(so, 1); |
|
5515 SCTP_TCB_LOCK(stcb); |
|
5516 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
5517 #endif |
|
5518 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT+SCTP_LOC_29); |
|
5519 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
5520 SCTP_SOCKET_UNLOCK(so, 1); |
|
5521 #endif |
|
5522 *offset = length; |
|
5523 return (NULL); |
|
5524 } |
|
5525 sctp_handle_forward_tsn(stcb, |
|
5526 (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset); |
|
5527 if (abort_flag) { |
|
5528 *offset = length; |
|
5529 return (NULL); |
|
5530 } else { |
|
5531 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
5532 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
5533 stcb->asoc.overall_error_count, |
|
5534 0, |
|
5535 SCTP_FROM_SCTP_INPUT, |
|
5536 __LINE__); |
|
5537 } |
|
5538 stcb->asoc.overall_error_count = 0; |
|
5539 } |
|
5540 |
|
5541 } |
|
5542 break; |
|
5543 case SCTP_STREAM_RESET: |
|
5544 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n"); |
|
5545 if (((stcb == NULL) || (ch == NULL) || (chk_length < sizeof(struct sctp_stream_reset_tsn_req)))) { |
|
5546 /* Its not ours */ |
|
5547 if (locked_tcb) { |
|
5548 SCTP_TCB_UNLOCK(locked_tcb); |
|
5549 } |
|
5550 *offset = length; |
|
5551 return (NULL); |
|
5552 } |
|
5553 if (stcb->asoc.peer_supports_strreset == 0) { |
|
5554 /* |
|
5555 * hmm, peer should have announced this, but |
|
5556 * we will turn it on since he is sending us |
|
5557 * a stream reset. |
|
5558 */ |
|
5559 stcb->asoc.peer_supports_strreset = 1; |
|
5560 } |
|
5561 if (sctp_handle_stream_reset(stcb, m, *offset, ch)) { |
|
5562 /* stop processing */ |
|
5563 *offset = length; |
|
5564 return (NULL); |
|
5565 } |
|
5566 break; |
|
5567 case SCTP_PACKET_DROPPED: |
|
5568 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_PACKET_DROPPED\n"); |
|
5569 /* re-get it all please */ |
|
5570 if (chk_length < sizeof(struct sctp_pktdrop_chunk)) { |
|
5571 /* Its not ours */ |
|
5572 if (locked_tcb) { |
|
5573 SCTP_TCB_UNLOCK(locked_tcb); |
|
5574 } |
|
5575 *offset = length; |
|
5576 return (NULL); |
|
5577 } |
|
5578 |
|
5579 |
|
5580 if (ch && (stcb) && netp && (*netp)) { |
|
5581 sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch, |
|
5582 stcb, *netp, |
|
5583 min(chk_length, (sizeof(chunk_buf) - 4))); |
|
5584 |
|
5585 } |
|
5586 |
|
5587 break; |
|
5588 |
|
5589 case SCTP_AUTHENTICATION: |
|
5590 SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_AUTHENTICATION\n"); |
|
5591 if (SCTP_BASE_SYSCTL(sctp_auth_disable)) |
|
5592 goto unknown_chunk; |
|
5593 |
|
5594 if (stcb == NULL) { |
|
5595 /* save the first AUTH for later processing */ |
|
5596 if (auth_skipped == 0) { |
|
5597 auth_offset = *offset; |
|
5598 auth_len = chk_length; |
|
5599 auth_skipped = 1; |
|
5600 } |
|
5601 /* skip this chunk (temporarily) */ |
|
5602 goto next_chunk; |
|
5603 } |
|
5604 if ((chk_length < (sizeof(struct sctp_auth_chunk))) || |
|
5605 (chk_length > (sizeof(struct sctp_auth_chunk) + |
|
5606 SCTP_AUTH_DIGEST_LEN_MAX))) { |
|
5607 /* Its not ours */ |
|
5608 if (locked_tcb) { |
|
5609 SCTP_TCB_UNLOCK(locked_tcb); |
|
5610 } |
|
5611 *offset = length; |
|
5612 return (NULL); |
|
5613 } |
|
5614 if (got_auth == 1) { |
|
5615 /* skip this chunk... it's already auth'd */ |
|
5616 goto next_chunk; |
|
5617 } |
|
5618 got_auth = 1; |
|
5619 if ((ch == NULL) || sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch, |
|
5620 m, *offset)) { |
|
5621 /* auth HMAC failed so dump the packet */ |
|
5622 *offset = length; |
|
5623 return (stcb); |
|
5624 } else { |
|
5625 /* remaining chunks are HMAC checked */ |
|
5626 stcb->asoc.authenticated = 1; |
|
5627 } |
|
5628 break; |
|
5629 |
|
5630 default: |
|
5631 unknown_chunk: |
|
5632 /* it's an unknown chunk! */ |
|
5633 if ((ch->chunk_type & 0x40) && (stcb != NULL)) { |
|
5634 struct mbuf *mm; |
|
5635 struct sctp_paramhdr *phd; |
|
5636 |
|
5637 mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
|
5638 0, M_NOWAIT, 1, MT_DATA); |
|
5639 if (mm) { |
|
5640 phd = mtod(mm, struct sctp_paramhdr *); |
|
5641 /* |
|
5642 * We cheat and use param type since |
|
5643 * we did not bother to define a |
|
5644 * error cause struct. They are the |
|
5645 * same basic format with different |
|
5646 * names. |
|
5647 */ |
|
5648 phd->param_type = htons(SCTP_CAUSE_UNRECOG_CHUNK); |
|
5649 phd->param_length = htons(chk_length + sizeof(*phd)); |
|
5650 SCTP_BUF_LEN(mm) = sizeof(*phd); |
|
5651 SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); |
|
5652 if (SCTP_BUF_NEXT(mm)) { |
|
5653 if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(mm), SCTP_SIZE32(chk_length) - chk_length, NULL)) { |
|
5654 sctp_m_freem(mm); |
|
5655 } else { |
|
5656 #ifdef SCTP_MBUF_LOGGING |
|
5657 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
|
5658 struct mbuf *mat; |
|
5659 |
|
5660 for (mat = SCTP_BUF_NEXT(mm); mat; mat = SCTP_BUF_NEXT(mat)) { |
|
5661 if (SCTP_BUF_IS_EXTENDED(mat)) { |
|
5662 sctp_log_mb(mat, SCTP_MBUF_ICOPY); |
|
5663 } |
|
5664 } |
|
5665 } |
|
5666 #endif |
|
5667 sctp_queue_op_err(stcb, mm); |
|
5668 } |
|
5669 } else { |
|
5670 sctp_m_freem(mm); |
|
5671 } |
|
5672 } |
|
5673 } |
|
5674 if ((ch->chunk_type & 0x80) == 0) { |
|
5675 /* discard this packet */ |
|
5676 *offset = length; |
|
5677 return (stcb); |
|
5678 } /* else skip this bad chunk and continue... */ |
|
5679 break; |
|
5680 } /* switch (ch->chunk_type) */ |
|
5681 |
|
5682 |
|
5683 next_chunk: |
|
5684 /* get the next chunk */ |
|
5685 *offset += SCTP_SIZE32(chk_length); |
|
5686 if (*offset >= length) { |
|
5687 /* no more data left in the mbuf chain */ |
|
5688 break; |
|
5689 } |
|
5690 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, |
|
5691 sizeof(struct sctp_chunkhdr), chunk_buf); |
|
5692 if (ch == NULL) { |
|
5693 if (locked_tcb) { |
|
5694 SCTP_TCB_UNLOCK(locked_tcb); |
|
5695 } |
|
5696 *offset = length; |
|
5697 return (NULL); |
|
5698 } |
|
5699 } /* while */ |
|
5700 |
|
5701 if (asconf_cnt > 0 && stcb != NULL) { |
|
5702 sctp_send_asconf_ack(stcb); |
|
5703 } |
|
5704 return (stcb); |
|
5705 } |
|
5706 |
|
5707 |
|
5708 #ifdef INVARIANTS |
|
5709 #ifdef __GNUC__ |
|
5710 __attribute__((noinline)) |
|
5711 #endif |
|
5712 void |
|
5713 sctp_validate_no_locks(struct sctp_inpcb *inp) |
|
5714 { |
|
5715 #ifndef __APPLE__ |
|
5716 struct sctp_tcb *lstcb; |
|
5717 |
|
5718 LIST_FOREACH(lstcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
5719 if (mtx_owned(&lstcb->tcb_mtx)) { |
|
5720 panic("Own lock on stcb at return from input"); |
|
5721 } |
|
5722 } |
|
5723 if (mtx_owned(&inp->inp_create_mtx)) { |
|
5724 panic("Own create lock on inp"); |
|
5725 } |
|
5726 if (mtx_owned(&inp->inp_mtx)) { |
|
5727 panic("Own inp lock on inp"); |
|
5728 } |
|
5729 #endif |
|
5730 } |
|
5731 #endif |
|
5732 |
|
5733 /* |
|
5734 * common input chunk processing (v4 and v6) |
|
5735 */ |
|
5736 void |
|
5737 sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int length, |
|
5738 struct sockaddr *src, struct sockaddr *dst, |
|
5739 struct sctphdr *sh, struct sctp_chunkhdr *ch, |
|
5740 #if !defined(SCTP_WITH_NO_CSUM) |
|
5741 uint8_t compute_crc, |
|
5742 #endif |
|
5743 uint8_t ecn_bits, |
|
5744 #if defined(__FreeBSD__) |
|
5745 uint8_t use_mflowid, uint32_t mflowid, |
|
5746 #endif |
|
5747 uint32_t vrf_id, uint16_t port) |
|
5748 { |
|
5749 uint32_t high_tsn; |
|
5750 int fwd_tsn_seen = 0, data_processed = 0; |
|
5751 struct mbuf *m = *mm; |
|
5752 int un_sent; |
|
5753 int cnt_ctrl_ready = 0; |
|
5754 struct sctp_inpcb *inp = NULL, *inp_decr = NULL; |
|
5755 struct sctp_tcb *stcb = NULL; |
|
5756 struct sctp_nets *net = NULL; |
|
5757 |
|
5758 SCTP_STAT_INCR(sctps_recvdatagrams); |
|
5759 #ifdef SCTP_AUDITING_ENABLED |
|
5760 sctp_audit_log(0xE0, 1); |
|
5761 sctp_auditing(0, inp, stcb, net); |
|
5762 #endif |
|
5763 #if !defined(SCTP_WITH_NO_CSUM) |
|
5764 if (compute_crc != 0) { |
|
5765 uint32_t check, calc_check; |
|
5766 |
|
5767 check = sh->checksum; |
|
5768 sh->checksum = 0; |
|
5769 calc_check = sctp_calculate_cksum(m, iphlen); |
|
5770 sh->checksum = check; |
|
5771 if (calc_check != check) { |
|
5772 SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", |
|
5773 calc_check, check, (void *)m, length, iphlen); |
|
5774 stcb = sctp_findassociation_addr(m, offset, src, dst, |
|
5775 sh, ch, &inp, &net, vrf_id); |
|
5776 if ((net != NULL) && (port != 0)) { |
|
5777 if (net->port == 0) { |
|
5778 sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); |
|
5779 } |
|
5780 net->port = port; |
|
5781 } |
|
5782 #if defined(__FreeBSD__) |
|
5783 if ((net != NULL) && (use_mflowid != 0)) { |
|
5784 net->flowid = mflowid; |
|
5785 #ifdef INVARIANTS |
|
5786 net->flowidset = 1; |
|
5787 #endif |
|
5788 } |
|
5789 #endif |
|
5790 if ((inp != NULL) && (stcb != NULL)) { |
|
5791 sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1); |
|
5792 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); |
|
5793 } else if ((inp != NULL) && (stcb == NULL)) { |
|
5794 inp_decr = inp; |
|
5795 } |
|
5796 SCTP_STAT_INCR(sctps_badsum); |
|
5797 SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); |
|
5798 goto out; |
|
5799 } |
|
5800 } |
|
5801 #endif |
|
5802 /* Destination port of 0 is illegal, based on RFC4960. */ |
|
5803 if (sh->dest_port == 0) { |
|
5804 SCTP_STAT_INCR(sctps_hdrops); |
|
5805 goto out; |
|
5806 } |
|
5807 stcb = sctp_findassociation_addr(m, offset, src, dst, |
|
5808 sh, ch, &inp, &net, vrf_id); |
|
5809 if ((net != NULL) && (port != 0)) { |
|
5810 if (net->port == 0) { |
|
5811 sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); |
|
5812 } |
|
5813 net->port = port; |
|
5814 } |
|
5815 #if defined(__FreeBSD__) |
|
5816 if ((net != NULL) && (use_mflowid != 0)) { |
|
5817 net->flowid = mflowid; |
|
5818 #ifdef INVARIANTS |
|
5819 net->flowidset = 1; |
|
5820 #endif |
|
5821 } |
|
5822 #endif |
|
5823 if (inp == NULL) { |
|
5824 SCTP_STAT_INCR(sctps_noport); |
|
5825 #if defined(__FreeBSD__) && (((__FreeBSD_version < 900000) && (__FreeBSD_version >= 804000)) || (__FreeBSD_version > 900000)) |
|
5826 if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) { |
|
5827 goto out; |
|
5828 } |
|
5829 #endif |
|
5830 if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { |
|
5831 sctp_send_shutdown_complete2(src, dst, sh, |
|
5832 #if defined(__FreeBSD__) |
|
5833 use_mflowid, mflowid, |
|
5834 #endif |
|
5835 vrf_id, port); |
|
5836 goto out; |
|
5837 } |
|
5838 if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { |
|
5839 goto out; |
|
5840 } |
|
5841 if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) { |
|
5842 if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || |
|
5843 ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && |
|
5844 (ch->chunk_type != SCTP_INIT))) { |
|
5845 sctp_send_abort(m, iphlen, src, dst, |
|
5846 sh, 0, NULL, |
|
5847 #if defined(__FreeBSD__) |
|
5848 use_mflowid, mflowid, |
|
5849 #endif |
|
5850 vrf_id, port); |
|
5851 } |
|
5852 } |
|
5853 goto out; |
|
5854 } else if (stcb == NULL) { |
|
5855 inp_decr = inp; |
|
5856 } |
|
5857 #ifdef IPSEC |
|
5858 /*- |
|
5859 * I very much doubt any of the IPSEC stuff will work but I have no |
|
5860 * idea, so I will leave it in place. |
|
5861 */ |
|
5862 if (inp != NULL) { |
|
5863 switch (dst->sa_family) { |
|
5864 #ifdef INET |
|
5865 case AF_INET: |
|
5866 if (ipsec4_in_reject(m, &inp->ip_inp.inp)) { |
|
5867 #if defined(__FreeBSD__) && (__FreeBSD_version > 1000036) |
|
5868 IPSECSTAT_INC(ips_in_polvio); |
|
5869 #else |
|
5870 MODULE_GLOBAL(ipsec4stat).in_polvio++; |
|
5871 #endif |
|
5872 SCTP_STAT_INCR(sctps_hdrops); |
|
5873 goto out; |
|
5874 } |
|
5875 break; |
|
5876 #endif |
|
5877 #ifdef INET6 |
|
5878 case AF_INET6: |
|
5879 if (ipsec6_in_reject(m, &inp->ip_inp.inp)) { |
|
5880 #if defined(__FreeBSD__) && (__FreeBSD_version > 1000036) |
|
5881 IPSEC6STAT_INC(ips_in_polvio); |
|
5882 #else |
|
5883 MODULE_GLOBAL(ipsec6stat).in_polvio++; |
|
5884 #endif |
|
5885 SCTP_STAT_INCR(sctps_hdrops); |
|
5886 goto out; |
|
5887 } |
|
5888 break; |
|
5889 #endif |
|
5890 default: |
|
5891 break; |
|
5892 } |
|
5893 } |
|
5894 #endif |
|
5895 SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n", |
|
5896 (void *)m, iphlen, offset, length, (void *)stcb); |
|
5897 if (stcb) { |
|
5898 /* always clear this before beginning a packet */ |
|
5899 stcb->asoc.authenticated = 0; |
|
5900 stcb->asoc.seen_a_sack_this_pkt = 0; |
|
5901 SCTPDBG(SCTP_DEBUG_INPUT1, "stcb:%p state:%x\n", |
|
5902 (void *)stcb, stcb->asoc.state); |
|
5903 |
|
5904 if ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) || |
|
5905 (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { |
|
5906 /*- |
|
5907 * If we hit here, we had a ref count |
|
5908 * up when the assoc was aborted and the |
|
5909 * timer is clearing out the assoc, we should |
|
5910 * NOT respond to any packet.. its OOTB. |
|
5911 */ |
|
5912 SCTP_TCB_UNLOCK(stcb); |
|
5913 stcb = NULL; |
|
5914 sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, |
|
5915 #if defined(__FreeBSD__) |
|
5916 use_mflowid, mflowid, |
|
5917 #endif |
|
5918 vrf_id, port); |
|
5919 goto out; |
|
5920 } |
|
5921 |
|
5922 } |
|
5923 if (IS_SCTP_CONTROL(ch)) { |
|
5924 /* process the control portion of the SCTP packet */ |
|
5925 /* sa_ignore NO_NULL_CHK */ |
|
5926 stcb = sctp_process_control(m, iphlen, &offset, length, |
|
5927 src, dst, sh, ch, |
|
5928 inp, stcb, &net, &fwd_tsn_seen, |
|
5929 #if defined(__FreeBSD__) |
|
5930 use_mflowid, mflowid, |
|
5931 #endif |
|
5932 vrf_id, port); |
|
5933 if (stcb) { |
|
5934 /* This covers us if the cookie-echo was there |
|
5935 * and it changes our INP. |
|
5936 */ |
|
5937 inp = stcb->sctp_ep; |
|
5938 if ((net) && (port)) { |
|
5939 if (net->port == 0) { |
|
5940 sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); |
|
5941 } |
|
5942 net->port = port; |
|
5943 } |
|
5944 } |
|
5945 } else { |
|
5946 /* |
|
5947 * no control chunks, so pre-process DATA chunks (these |
|
5948 * checks are taken care of by control processing) |
|
5949 */ |
|
5950 |
|
5951 /* |
|
5952 * if DATA only packet, and auth is required, then punt... |
|
5953 * can't have authenticated without any AUTH (control) |
|
5954 * chunks |
|
5955 */ |
|
5956 if ((stcb != NULL) && |
|
5957 !SCTP_BASE_SYSCTL(sctp_auth_disable) && |
|
5958 sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks)) { |
|
5959 /* "silently" ignore */ |
|
5960 SCTP_STAT_INCR(sctps_recvauthmissing); |
|
5961 goto out; |
|
5962 } |
|
5963 if (stcb == NULL) { |
|
5964 /* out of the blue DATA chunk */ |
|
5965 sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, |
|
5966 #if defined(__FreeBSD__) |
|
5967 use_mflowid, mflowid, |
|
5968 #endif |
|
5969 vrf_id, port); |
|
5970 goto out; |
|
5971 } |
|
5972 if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) { |
|
5973 /* v_tag mismatch! */ |
|
5974 SCTP_STAT_INCR(sctps_badvtag); |
|
5975 goto out; |
|
5976 } |
|
5977 } |
|
5978 |
|
5979 if (stcb == NULL) { |
|
5980 /* |
|
5981 * no valid TCB for this packet, or we found it's a bad |
|
5982 * packet while processing control, or we're done with this |
|
5983 * packet (done or skip rest of data), so we drop it... |
|
5984 */ |
|
5985 goto out; |
|
5986 } |
|
5987 |
|
5988 /* |
|
5989 * DATA chunk processing |
|
5990 */ |
|
5991 /* plow through the data chunks while length > offset */ |
|
5992 |
|
5993 /* |
|
5994 * Rest should be DATA only. Check authentication state if AUTH for |
|
5995 * DATA is required. |
|
5996 */ |
|
5997 if ((length > offset) && |
|
5998 (stcb != NULL) && |
|
5999 !SCTP_BASE_SYSCTL(sctp_auth_disable) && |
|
6000 sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks) && |
|
6001 !stcb->asoc.authenticated) { |
|
6002 /* "silently" ignore */ |
|
6003 SCTP_STAT_INCR(sctps_recvauthmissing); |
|
6004 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
6005 "Data chunk requires AUTH, skipped\n"); |
|
6006 goto trigger_send; |
|
6007 } |
|
6008 if (length > offset) { |
|
6009 int retval; |
|
6010 |
|
6011 /* |
|
6012 * First check to make sure our state is correct. We would |
|
6013 * not get here unless we really did have a tag, so we don't |
|
6014 * abort if this happens, just dump the chunk silently. |
|
6015 */ |
|
6016 switch (SCTP_GET_STATE(&stcb->asoc)) { |
|
6017 case SCTP_STATE_COOKIE_ECHOED: |
|
6018 /* |
|
6019 * we consider data with valid tags in this state |
|
6020 * shows us the cookie-ack was lost. Imply it was |
|
6021 * there. |
|
6022 */ |
|
6023 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
6024 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
6025 stcb->asoc.overall_error_count, |
|
6026 0, |
|
6027 SCTP_FROM_SCTP_INPUT, |
|
6028 __LINE__); |
|
6029 } |
|
6030 stcb->asoc.overall_error_count = 0; |
|
6031 sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, net); |
|
6032 break; |
|
6033 case SCTP_STATE_COOKIE_WAIT: |
|
6034 /* |
|
6035 * We consider OOTB any data sent during asoc setup. |
|
6036 */ |
|
6037 sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp, |
|
6038 #if defined(__FreeBSD__) |
|
6039 use_mflowid, mflowid, |
|
6040 #endif |
|
6041 vrf_id, port); |
|
6042 goto out; |
|
6043 /*sa_ignore NOTREACHED*/ |
|
6044 break; |
|
6045 case SCTP_STATE_EMPTY: /* should not happen */ |
|
6046 case SCTP_STATE_INUSE: /* should not happen */ |
|
6047 case SCTP_STATE_SHUTDOWN_RECEIVED: /* This is a peer error */ |
|
6048 case SCTP_STATE_SHUTDOWN_ACK_SENT: |
|
6049 default: |
|
6050 goto out; |
|
6051 /*sa_ignore NOTREACHED*/ |
|
6052 break; |
|
6053 case SCTP_STATE_OPEN: |
|
6054 case SCTP_STATE_SHUTDOWN_SENT: |
|
6055 break; |
|
6056 } |
|
6057 /* plow through the data chunks while length > offset */ |
|
6058 retval = sctp_process_data(mm, iphlen, &offset, length, |
|
6059 src, dst, sh, |
|
6060 inp, stcb, net, &high_tsn, |
|
6061 #if defined(__FreeBSD__) |
|
6062 use_mflowid, mflowid, |
|
6063 #endif |
|
6064 vrf_id, port); |
|
6065 if (retval == 2) { |
|
6066 /* |
|
6067 * The association aborted, NO UNLOCK needed since |
|
6068 * the association is destroyed. |
|
6069 */ |
|
6070 stcb = NULL; |
|
6071 goto out; |
|
6072 } |
|
6073 data_processed = 1; |
|
6074 /* |
|
6075 * Anything important needs to have been m_copy'ed in |
|
6076 * process_data |
|
6077 */ |
|
6078 } |
|
6079 |
|
6080 /* take care of ecn */ |
|
6081 if ((data_processed == 1) && |
|
6082 (stcb->asoc.ecn_allowed == 1) && |
|
6083 ((ecn_bits & SCTP_CE_BITS) == SCTP_CE_BITS)) { |
|
6084 /* Yep, we need to add a ECNE */ |
|
6085 sctp_send_ecn_echo(stcb, net, high_tsn); |
|
6086 } |
|
6087 |
|
6088 if ((data_processed == 0) && (fwd_tsn_seen)) { |
|
6089 int was_a_gap; |
|
6090 uint32_t highest_tsn; |
|
6091 |
|
6092 if (SCTP_TSN_GT(stcb->asoc.highest_tsn_inside_nr_map, stcb->asoc.highest_tsn_inside_map)) { |
|
6093 highest_tsn = stcb->asoc.highest_tsn_inside_nr_map; |
|
6094 } else { |
|
6095 highest_tsn = stcb->asoc.highest_tsn_inside_map; |
|
6096 } |
|
6097 was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn); |
|
6098 stcb->asoc.send_sack = 1; |
|
6099 sctp_sack_check(stcb, was_a_gap); |
|
6100 } else if (fwd_tsn_seen) { |
|
6101 stcb->asoc.send_sack = 1; |
|
6102 } |
|
6103 /* trigger send of any chunks in queue... */ |
|
6104 trigger_send: |
|
6105 #ifdef SCTP_AUDITING_ENABLED |
|
6106 sctp_audit_log(0xE0, 2); |
|
6107 sctp_auditing(1, inp, stcb, net); |
|
6108 #endif |
|
6109 SCTPDBG(SCTP_DEBUG_INPUT1, |
|
6110 "Check for chunk output prw:%d tqe:%d tf=%d\n", |
|
6111 stcb->asoc.peers_rwnd, |
|
6112 TAILQ_EMPTY(&stcb->asoc.control_send_queue), |
|
6113 stcb->asoc.total_flight); |
|
6114 un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); |
|
6115 if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { |
|
6116 cnt_ctrl_ready = stcb->asoc.ctrl_queue_cnt - stcb->asoc.ecn_echo_cnt_onq; |
|
6117 } |
|
6118 if (cnt_ctrl_ready || |
|
6119 ((un_sent) && |
|
6120 (stcb->asoc.peers_rwnd > 0 || |
|
6121 (stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) { |
|
6122 SCTPDBG(SCTP_DEBUG_INPUT3, "Calling chunk OUTPUT\n"); |
|
6123 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); |
|
6124 SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n"); |
|
6125 } |
|
6126 #ifdef SCTP_AUDITING_ENABLED |
|
6127 sctp_audit_log(0xE0, 3); |
|
6128 sctp_auditing(2, inp, stcb, net); |
|
6129 #endif |
|
6130 out: |
|
6131 if (stcb != NULL) { |
|
6132 SCTP_TCB_UNLOCK(stcb); |
|
6133 } |
|
6134 if (inp_decr != NULL) { |
|
6135 /* reduce ref-count */ |
|
6136 SCTP_INP_WLOCK(inp_decr); |
|
6137 SCTP_INP_DECR_REF(inp_decr); |
|
6138 SCTP_INP_WUNLOCK(inp_decr); |
|
6139 } |
|
6140 #ifdef INVARIANTS |
|
6141 if (inp != NULL) { |
|
6142 sctp_validate_no_locks(inp); |
|
6143 } |
|
6144 #endif |
|
6145 return; |
|
6146 } |
|
6147 |
|
6148 #if 0 |
|
6149 static void |
|
6150 sctp_print_mbuf_chain(struct mbuf *m) |
|
6151 { |
|
6152 for (; m; m = SCTP_BUF_NEXT(m)) { |
|
6153 SCTP_PRINTF("%p: m_len = %ld\n", (void *)m, SCTP_BUF_LEN(m)); |
|
6154 if (SCTP_BUF_IS_EXTENDED(m)) |
|
6155 SCTP_PRINTF("%p: extend_size = %d\n", (void *)m, SCTP_BUF_EXTEND_SIZE(m)); |
|
6156 } |
|
6157 } |
|
6158 #endif |
|
6159 |
|
6160 #ifdef INET |
|
6161 #if !defined(__Userspace__) |
|
6162 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
6163 void |
|
6164 sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) |
|
6165 #elif defined(__Panda__) |
|
6166 void |
|
6167 sctp_input(pakhandle_type i_pak) |
|
6168 #else |
|
6169 void |
|
6170 #if __STDC__ |
|
6171 sctp_input(struct mbuf *i_pak,...) |
|
6172 #else |
|
6173 sctp_input(i_pak, va_alist) |
|
6174 struct mbuf *i_pak; |
|
6175 #endif |
|
6176 #endif |
|
6177 { |
|
6178 struct mbuf *m; |
|
6179 int iphlen; |
|
6180 uint32_t vrf_id = 0; |
|
6181 uint8_t ecn_bits; |
|
6182 struct sockaddr_in src, dst; |
|
6183 struct ip *ip; |
|
6184 struct sctphdr *sh; |
|
6185 struct sctp_chunkhdr *ch; |
|
6186 int length, offset; |
|
6187 #if !defined(SCTP_WITH_NO_CSUM) |
|
6188 uint8_t compute_crc; |
|
6189 #endif |
|
6190 #if defined(__FreeBSD__) |
|
6191 uint32_t mflowid; |
|
6192 uint8_t use_mflowid; |
|
6193 #endif |
|
6194 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)) |
|
6195 uint16_t port = 0; |
|
6196 #endif |
|
6197 |
|
6198 #if defined(__Panda__) |
|
6199 /* This is Evil, but its the only way to make panda work right. */ |
|
6200 iphlen = sizeof(struct ip); |
|
6201 #else |
|
6202 iphlen = off; |
|
6203 #endif |
|
6204 if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) { |
|
6205 SCTP_RELEASE_PKT(i_pak); |
|
6206 return; |
|
6207 } |
|
6208 m = SCTP_HEADER_TO_CHAIN(i_pak); |
|
6209 #ifdef __Panda__ |
|
6210 SCTP_DETACH_HEADER_FROM_CHAIN(i_pak); |
|
6211 (void)SCTP_RELEASE_HEADER(i_pak); |
|
6212 #endif |
|
6213 #ifdef SCTP_MBUF_LOGGING |
|
6214 /* Log in any input mbufs */ |
|
6215 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
|
6216 struct mbuf *mat; |
|
6217 |
|
6218 for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { |
|
6219 if (SCTP_BUF_IS_EXTENDED(mat)) { |
|
6220 sctp_log_mb(mat, SCTP_MBUF_INPUT); |
|
6221 } |
|
6222 } |
|
6223 } |
|
6224 #endif |
|
6225 #ifdef SCTP_PACKET_LOGGING |
|
6226 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { |
|
6227 sctp_packet_log(m); |
|
6228 } |
|
6229 #endif |
|
6230 #if defined(__FreeBSD__) |
|
6231 #if __FreeBSD_version > 1000049 |
|
6232 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, |
|
6233 "sctp_input(): Packet of length %d received on %s with csum_flags 0x%b.\n", |
|
6234 m->m_pkthdr.len, |
|
6235 if_name(m->m_pkthdr.rcvif), |
|
6236 (int)m->m_pkthdr.csum_flags, CSUM_BITS); |
|
6237 #elif __FreeBSD_version >= 800000 |
|
6238 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, |
|
6239 "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", |
|
6240 m->m_pkthdr.len, |
|
6241 if_name(m->m_pkthdr.rcvif), |
|
6242 m->m_pkthdr.csum_flags); |
|
6243 #else |
|
6244 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, |
|
6245 "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", |
|
6246 m->m_pkthdr.len, |
|
6247 m->m_pkthdr.rcvif->if_xname, |
|
6248 m->m_pkthdr.csum_flags); |
|
6249 #endif |
|
6250 #endif |
|
6251 #if defined(__APPLE__) |
|
6252 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, |
|
6253 "sctp_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n", |
|
6254 m->m_pkthdr.len, |
|
6255 m->m_pkthdr.rcvif->if_name, |
|
6256 m->m_pkthdr.rcvif->if_unit, |
|
6257 m->m_pkthdr.csum_flags); |
|
6258 #endif |
|
6259 #if defined(__Windows__) |
|
6260 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, |
|
6261 "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", |
|
6262 m->m_pkthdr.len, |
|
6263 m->m_pkthdr.rcvif->if_xname, |
|
6264 m->m_pkthdr.csum_flags); |
|
6265 #endif |
|
6266 #if defined(__FreeBSD__) |
|
6267 if (m->m_flags & M_FLOWID) { |
|
6268 mflowid = m->m_pkthdr.flowid; |
|
6269 use_mflowid = 1; |
|
6270 } else { |
|
6271 mflowid = 0; |
|
6272 use_mflowid = 0; |
|
6273 } |
|
6274 #endif |
|
6275 SCTP_STAT_INCR(sctps_recvpackets); |
|
6276 SCTP_STAT_INCR_COUNTER64(sctps_inpackets); |
|
6277 /* Get IP, SCTP, and first chunk header together in the first mbuf. */ |
|
6278 offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); |
|
6279 if (SCTP_BUF_LEN(m) < offset) { |
|
6280 if ((m = m_pullup(m, offset)) == NULL) { |
|
6281 SCTP_STAT_INCR(sctps_hdrops); |
|
6282 return; |
|
6283 } |
|
6284 } |
|
6285 ip = mtod(m, struct ip *); |
|
6286 sh = (struct sctphdr *)((caddr_t)ip + iphlen); |
|
6287 ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); |
|
6288 offset -= sizeof(struct sctp_chunkhdr); |
|
6289 memset(&src, 0, sizeof(struct sockaddr_in)); |
|
6290 src.sin_family = AF_INET; |
|
6291 #ifdef HAVE_SIN_LEN |
|
6292 src.sin_len = sizeof(struct sockaddr_in); |
|
6293 #endif |
|
6294 src.sin_port = sh->src_port; |
|
6295 src.sin_addr = ip->ip_src; |
|
6296 memset(&dst, 0, sizeof(struct sockaddr_in)); |
|
6297 dst.sin_family = AF_INET; |
|
6298 #ifdef HAVE_SIN_LEN |
|
6299 dst.sin_len = sizeof(struct sockaddr_in); |
|
6300 #endif |
|
6301 dst.sin_port = sh->dest_port; |
|
6302 dst.sin_addr = ip->ip_dst; |
|
6303 #if defined(__Windows__) |
|
6304 NTOHS(ip->ip_len); |
|
6305 #endif |
|
6306 #if defined(__Userspace_os_Linux) || defined(__Userspace_os_Windows) |
|
6307 ip->ip_len = ntohs(ip->ip_len); |
|
6308 #endif |
|
6309 #if defined(__FreeBSD__) |
|
6310 #if __FreeBSD_version >= 1000000 |
|
6311 length = ntohs(ip->ip_len); |
|
6312 #else |
|
6313 length = ip->ip_len + iphlen; |
|
6314 #endif |
|
6315 #elif defined(__APPLE__) |
|
6316 length = ip->ip_len + iphlen; |
|
6317 #elif defined(__Userspace__) |
|
6318 #if defined(__Userspace_os_Linux) || defined(__Userspace_os_Windows) |
|
6319 length = ip->ip_len; |
|
6320 #else |
|
6321 length = ip->ip_len + iphlen; |
|
6322 #endif |
|
6323 #else |
|
6324 length = ip->ip_len; |
|
6325 #endif |
|
6326 /* Validate mbuf chain length with IP payload length. */ |
|
6327 if (SCTP_HEADER_LEN(m) != length) { |
|
6328 SCTPDBG(SCTP_DEBUG_INPUT1, |
|
6329 "sctp_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m)); |
|
6330 SCTP_STAT_INCR(sctps_hdrops); |
|
6331 goto out; |
|
6332 } |
|
6333 /* SCTP does not allow broadcasts or multicasts */ |
|
6334 if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { |
|
6335 goto out; |
|
6336 } |
|
6337 if (SCTP_IS_IT_BROADCAST(dst.sin_addr, m)) { |
|
6338 goto out; |
|
6339 } |
|
6340 ecn_bits = ip->ip_tos; |
|
6341 #if defined(SCTP_WITH_NO_CSUM) |
|
6342 SCTP_STAT_INCR(sctps_recvnocrc); |
|
6343 #else |
|
6344 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6345 if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { |
|
6346 SCTP_STAT_INCR(sctps_recvhwcrc); |
|
6347 compute_crc = 0; |
|
6348 } else { |
|
6349 #else |
|
6350 if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && |
|
6351 ((src.sin_addr.s_addr == dst.sin_addr.s_addr) || |
|
6352 (SCTP_IS_IT_LOOPBACK(m)))) { |
|
6353 SCTP_STAT_INCR(sctps_recvnocrc); |
|
6354 compute_crc = 0; |
|
6355 } else { |
|
6356 #endif |
|
6357 SCTP_STAT_INCR(sctps_recvswcrc); |
|
6358 compute_crc = 1; |
|
6359 } |
|
6360 #endif |
|
6361 sctp_common_input_processing(&m, iphlen, offset, length, |
|
6362 (struct sockaddr *)&src, |
|
6363 (struct sockaddr *)&dst, |
|
6364 sh, ch, |
|
6365 #if !defined(SCTP_WITH_NO_CSUM) |
|
6366 compute_crc, |
|
6367 #endif |
|
6368 ecn_bits, |
|
6369 #if defined(__FreeBSD__) |
|
6370 use_mflowid, mflowid, |
|
6371 #endif |
|
6372 vrf_id, port); |
|
6373 out: |
|
6374 if (m) { |
|
6375 sctp_m_freem(m); |
|
6376 } |
|
6377 return; |
|
6378 } |
|
6379 |
|
6380 #if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP) |
|
6381 extern int *sctp_cpuarry; |
|
6382 #endif |
|
6383 |
|
6384 void |
|
6385 sctp_input(struct mbuf *m, int off) |
|
6386 { |
|
6387 #if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP) |
|
6388 struct ip *ip; |
|
6389 struct sctphdr *sh; |
|
6390 int offset; |
|
6391 int cpu_to_use; |
|
6392 uint32_t flowid, tag; |
|
6393 |
|
6394 if (mp_ncpus > 1) { |
|
6395 if (m->m_flags & M_FLOWID) { |
|
6396 flowid = m->m_pkthdr.flowid; |
|
6397 } else { |
|
6398 /* No flow id built by lower layers |
|
6399 * fix it so we create one. |
|
6400 */ |
|
6401 offset = off + sizeof(struct sctphdr); |
|
6402 if (SCTP_BUF_LEN(m) < offset) { |
|
6403 if ((m = m_pullup(m, offset)) == NULL) { |
|
6404 SCTP_STAT_INCR(sctps_hdrops); |
|
6405 return; |
|
6406 } |
|
6407 } |
|
6408 ip = mtod(m, struct ip *); |
|
6409 sh = (struct sctphdr *)((caddr_t)ip + off); |
|
6410 tag = htonl(sh->v_tag); |
|
6411 flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); |
|
6412 m->m_pkthdr.flowid = flowid; |
|
6413 m->m_flags |= M_FLOWID; |
|
6414 } |
|
6415 cpu_to_use = sctp_cpuarry[flowid % mp_ncpus]; |
|
6416 sctp_queue_to_mcore(m, off, cpu_to_use); |
|
6417 return; |
|
6418 } |
|
6419 #endif |
|
6420 sctp_input_with_port(m, off, 0); |
|
6421 } |
|
6422 #endif |
|
6423 #endif |