Deleted Added
full compact
tcp_syncache.c (181337) tcp_syncache.c (181803)
1/*-
2 * Copyright (c) 2001 McAfee, Inc.
3 * Copyright (c) 2006 Andre Oppermann, Internet Business Solutions AG
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Jonathan Lemon
7 * and McAfee Research, the Security Research Division of McAfee, Inc. under
8 * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the

--- 17 unchanged lines hidden (view full) ---

26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2001 McAfee, Inc.
3 * Copyright (c) 2006 Andre Oppermann, Internet Business Solutions AG
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Jonathan Lemon
7 * and McAfee Research, the Security Research Division of McAfee, Inc. under
8 * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the

--- 17 unchanged lines hidden (view full) ---

26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/netinet/tcp_syncache.c 181337 2008-08-05 21:59:20Z jhb $");
34__FBSDID("$FreeBSD: head/sys/netinet/tcp_syncache.c 181803 2008-08-17 23:27:27Z bz $");
35
36#include "opt_inet.h"
37#include "opt_inet6.h"
38#include "opt_ipsec.h"
39#include "opt_mac.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>

--- 5 unchanged lines hidden (view full) ---

48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/md5.h>
51#include <sys/proc.h> /* for proc0 declaration */
52#include <sys/random.h>
53#include <sys/socket.h>
54#include <sys/socketvar.h>
55#include <sys/syslog.h>
35
36#include "opt_inet.h"
37#include "opt_inet6.h"
38#include "opt_ipsec.h"
39#include "opt_mac.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>

--- 5 unchanged lines hidden (view full) ---

48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/md5.h>
51#include <sys/proc.h> /* for proc0 declaration */
52#include <sys/random.h>
53#include <sys/socket.h>
54#include <sys/socketvar.h>
55#include <sys/syslog.h>
56#include <sys/vimage.h>
56
57#include <vm/uma.h>
58
59#include <net/if.h>
60#include <net/route.h>
61
62#include <netinet/in.h>
63#include <netinet/in_systm.h>

--- 162 unchanged lines hidden (view full) ---

226
227int tcp_sc_rst_sock_fail = 1;
228SYSCTL_INT(_net_inet_tcp_syncache, OID_AUTO, rst_on_sock_fail, CTLFLAG_RW,
229 &tcp_sc_rst_sock_fail, 0, "Send reset on socket allocation failure");
230
231static MALLOC_DEFINE(M_SYNCACHE, "syncache", "TCP syncache");
232
233#define SYNCACHE_HASH(inc, mask) \
57
58#include <vm/uma.h>
59
60#include <net/if.h>
61#include <net/route.h>
62
63#include <netinet/in.h>
64#include <netinet/in_systm.h>

--- 162 unchanged lines hidden (view full) ---

227
228int tcp_sc_rst_sock_fail = 1;
229SYSCTL_INT(_net_inet_tcp_syncache, OID_AUTO, rst_on_sock_fail, CTLFLAG_RW,
230 &tcp_sc_rst_sock_fail, 0, "Send reset on socket allocation failure");
231
232static MALLOC_DEFINE(M_SYNCACHE, "syncache", "TCP syncache");
233
234#define SYNCACHE_HASH(inc, mask) \
234 ((tcp_syncache.hash_secret ^ \
235 ((V_tcp_syncache.hash_secret ^ \
235 (inc)->inc_faddr.s_addr ^ \
236 ((inc)->inc_faddr.s_addr >> 16) ^ \
237 (inc)->inc_fport ^ (inc)->inc_lport) & mask)
238
239#define SYNCACHE_HASH6(inc, mask) \
236 (inc)->inc_faddr.s_addr ^ \
237 ((inc)->inc_faddr.s_addr >> 16) ^ \
238 (inc)->inc_fport ^ (inc)->inc_lport) & mask)
239
240#define SYNCACHE_HASH6(inc, mask) \
240 ((tcp_syncache.hash_secret ^ \
241 ((V_tcp_syncache.hash_secret ^ \
241 (inc)->inc6_faddr.s6_addr32[0] ^ \
242 (inc)->inc6_faddr.s6_addr32[3] ^ \
243 (inc)->inc_fport ^ (inc)->inc_lport) & mask)
244
245#define ENDPTS_EQ(a, b) ( \
246 (a)->ie_fport == (b)->ie_fport && \
247 (a)->ie_lport == (b)->ie_lport && \
248 (a)->ie_faddr.s_addr == (b)->ie_faddr.s_addr && \

--- 13 unchanged lines hidden (view full) ---

262syncache_free(struct syncache *sc)
263{
264 if (sc->sc_ipopts)
265 (void) m_free(sc->sc_ipopts);
266#ifdef MAC
267 mac_syncache_destroy(&sc->sc_label);
268#endif
269
242 (inc)->inc6_faddr.s6_addr32[0] ^ \
243 (inc)->inc6_faddr.s6_addr32[3] ^ \
244 (inc)->inc_fport ^ (inc)->inc_lport) & mask)
245
246#define ENDPTS_EQ(a, b) ( \
247 (a)->ie_fport == (b)->ie_fport && \
248 (a)->ie_lport == (b)->ie_lport && \
249 (a)->ie_faddr.s_addr == (b)->ie_faddr.s_addr && \

--- 13 unchanged lines hidden (view full) ---

263syncache_free(struct syncache *sc)
264{
265 if (sc->sc_ipopts)
266 (void) m_free(sc->sc_ipopts);
267#ifdef MAC
268 mac_syncache_destroy(&sc->sc_label);
269#endif
270
270 uma_zfree(tcp_syncache.zone, sc);
271 uma_zfree(V_tcp_syncache.zone, sc);
271}
272
273void
274syncache_init(void)
275{
276 int i;
277
272}
273
274void
275syncache_init(void)
276{
277 int i;
278
278 tcp_syncache.cache_count = 0;
279 tcp_syncache.hashsize = TCP_SYNCACHE_HASHSIZE;
280 tcp_syncache.bucket_limit = TCP_SYNCACHE_BUCKETLIMIT;
281 tcp_syncache.rexmt_limit = SYNCACHE_MAXREXMTS;
282 tcp_syncache.hash_secret = arc4random();
279 V_tcp_syncache.cache_count = 0;
280 V_tcp_syncache.hashsize = TCP_SYNCACHE_HASHSIZE;
281 V_tcp_syncache.bucket_limit = TCP_SYNCACHE_BUCKETLIMIT;
282 V_tcp_syncache.rexmt_limit = SYNCACHE_MAXREXMTS;
283 V_tcp_syncache.hash_secret = arc4random();
283
284 TUNABLE_INT_FETCH("net.inet.tcp.syncache.hashsize",
284
285 TUNABLE_INT_FETCH("net.inet.tcp.syncache.hashsize",
285 &tcp_syncache.hashsize);
286 &V_tcp_syncache.hashsize);
286 TUNABLE_INT_FETCH("net.inet.tcp.syncache.bucketlimit",
287 TUNABLE_INT_FETCH("net.inet.tcp.syncache.bucketlimit",
287 &tcp_syncache.bucket_limit);
288 if (!powerof2(tcp_syncache.hashsize) || tcp_syncache.hashsize == 0) {
288 &V_tcp_syncache.bucket_limit);
289 if (!powerof2(V_tcp_syncache.hashsize) || V_tcp_syncache.hashsize == 0) {
289 printf("WARNING: syncache hash size is not a power of 2.\n");
290 printf("WARNING: syncache hash size is not a power of 2.\n");
290 tcp_syncache.hashsize = TCP_SYNCACHE_HASHSIZE;
291 V_tcp_syncache.hashsize = TCP_SYNCACHE_HASHSIZE;
291 }
292 }
292 tcp_syncache.hashmask = tcp_syncache.hashsize - 1;
293 V_tcp_syncache.hashmask = V_tcp_syncache.hashsize - 1;
293
294 /* Set limits. */
294
295 /* Set limits. */
295 tcp_syncache.cache_limit =
296 tcp_syncache.hashsize * tcp_syncache.bucket_limit;
296 V_tcp_syncache.cache_limit =
297 V_tcp_syncache.hashsize * V_tcp_syncache.bucket_limit;
297 TUNABLE_INT_FETCH("net.inet.tcp.syncache.cachelimit",
298 TUNABLE_INT_FETCH("net.inet.tcp.syncache.cachelimit",
298 &tcp_syncache.cache_limit);
299 &V_tcp_syncache.cache_limit);
299
300 /* Allocate the hash table. */
300
301 /* Allocate the hash table. */
301 MALLOC(tcp_syncache.hashbase, struct syncache_head *,
302 tcp_syncache.hashsize * sizeof(struct syncache_head),
302 MALLOC(V_tcp_syncache.hashbase, struct syncache_head *,
303 V_tcp_syncache.hashsize * sizeof(struct syncache_head),
303 M_SYNCACHE, M_WAITOK | M_ZERO);
304
305 /* Initialize the hash buckets. */
304 M_SYNCACHE, M_WAITOK | M_ZERO);
305
306 /* Initialize the hash buckets. */
306 for (i = 0; i < tcp_syncache.hashsize; i++) {
307 TAILQ_INIT(&tcp_syncache.hashbase[i].sch_bucket);
308 mtx_init(&tcp_syncache.hashbase[i].sch_mtx, "tcp_sc_head",
307 for (i = 0; i < V_tcp_syncache.hashsize; i++) {
308 TAILQ_INIT(&V_tcp_syncache.hashbase[i].sch_bucket);
309 mtx_init(&V_tcp_syncache.hashbase[i].sch_mtx, "tcp_sc_head",
309 NULL, MTX_DEF);
310 NULL, MTX_DEF);
310 callout_init_mtx(&tcp_syncache.hashbase[i].sch_timer,
311 &tcp_syncache.hashbase[i].sch_mtx, 0);
312 tcp_syncache.hashbase[i].sch_length = 0;
311 callout_init_mtx(&V_tcp_syncache.hashbase[i].sch_timer,
312 &V_tcp_syncache.hashbase[i].sch_mtx, 0);
313 V_tcp_syncache.hashbase[i].sch_length = 0;
313 }
314
315 /* Create the syncache entry zone. */
314 }
315
316 /* Create the syncache entry zone. */
316 tcp_syncache.zone = uma_zcreate("syncache", sizeof(struct syncache),
317 V_tcp_syncache.zone = uma_zcreate("syncache", sizeof(struct syncache),
317 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
318 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
318 uma_zone_set_max(tcp_syncache.zone, tcp_syncache.cache_limit);
319 uma_zone_set_max(V_tcp_syncache.zone, V_tcp_syncache.cache_limit);
319}
320
321/*
322 * Inserts a syncache entry into the specified bucket row.
323 * Locks and unlocks the syncache_head autonomously.
324 */
325static void
326syncache_insert(struct syncache *sc, struct syncache_head *sch)
327{
328 struct syncache *sc2;
329
330 SCH_LOCK(sch);
331
332 /*
333 * Make sure that we don't overflow the per-bucket limit.
334 * If the bucket is full, toss the oldest element.
335 */
320}
321
322/*
323 * Inserts a syncache entry into the specified bucket row.
324 * Locks and unlocks the syncache_head autonomously.
325 */
326static void
327syncache_insert(struct syncache *sc, struct syncache_head *sch)
328{
329 struct syncache *sc2;
330
331 SCH_LOCK(sch);
332
333 /*
334 * Make sure that we don't overflow the per-bucket limit.
335 * If the bucket is full, toss the oldest element.
336 */
336 if (sch->sch_length >= tcp_syncache.bucket_limit) {
337 if (sch->sch_length >= V_tcp_syncache.bucket_limit) {
337 KASSERT(!TAILQ_EMPTY(&sch->sch_bucket),
338 ("sch->sch_length incorrect"));
339 sc2 = TAILQ_LAST(&sch->sch_bucket, sch_head);
340 syncache_drop(sc2, sch);
338 KASSERT(!TAILQ_EMPTY(&sch->sch_bucket),
339 ("sch->sch_length incorrect"));
340 sc2 = TAILQ_LAST(&sch->sch_bucket, sch_head);
341 syncache_drop(sc2, sch);
341 tcpstat.tcps_sc_bucketoverflow++;
342 V_tcpstat.tcps_sc_bucketoverflow++;
342 }
343
344 /* Put it into the bucket. */
345 TAILQ_INSERT_HEAD(&sch->sch_bucket, sc, sc_hash);
346 sch->sch_length++;
347
348 /* Reinitialize the bucket row's timer. */
349 if (sch->sch_length == 1)
350 sch->sch_nextc = ticks + INT_MAX;
351 syncache_timeout(sc, sch, 1);
352
353 SCH_UNLOCK(sch);
354
343 }
344
345 /* Put it into the bucket. */
346 TAILQ_INSERT_HEAD(&sch->sch_bucket, sc, sc_hash);
347 sch->sch_length++;
348
349 /* Reinitialize the bucket row's timer. */
350 if (sch->sch_length == 1)
351 sch->sch_nextc = ticks + INT_MAX;
352 syncache_timeout(sc, sch, 1);
353
354 SCH_UNLOCK(sch);
355
355 tcp_syncache.cache_count++;
356 tcpstat.tcps_sc_added++;
356 V_tcp_syncache.cache_count++;
357 V_tcpstat.tcps_sc_added++;
357}
358
359/*
360 * Remove and free entry from syncache bucket row.
361 * Expects locked syncache head.
362 */
363static void
364syncache_drop(struct syncache *sc, struct syncache_head *sch)

--- 4 unchanged lines hidden (view full) ---

369 TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
370 sch->sch_length--;
371
372#ifndef TCP_OFFLOAD_DISABLE
373 if (sc->sc_tu)
374 sc->sc_tu->tu_syncache_event(TOE_SC_DROP, sc->sc_toepcb);
375#endif
376 syncache_free(sc);
358}
359
360/*
361 * Remove and free entry from syncache bucket row.
362 * Expects locked syncache head.
363 */
364static void
365syncache_drop(struct syncache *sc, struct syncache_head *sch)

--- 4 unchanged lines hidden (view full) ---

370 TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
371 sch->sch_length--;
372
373#ifndef TCP_OFFLOAD_DISABLE
374 if (sc->sc_tu)
375 sc->sc_tu->tu_syncache_event(TOE_SC_DROP, sc->sc_toepcb);
376#endif
377 syncache_free(sc);
377 tcp_syncache.cache_count--;
378 V_tcp_syncache.cache_count--;
378}
379
380/*
381 * Engage/reengage time on bucket row.
382 */
383static void
384syncache_timeout(struct syncache *sc, struct syncache_head *sch, int docallout)
385{

--- 39 unchanged lines hidden (view full) ---

425 * then the RST will be sent by the time the remote
426 * host does the SYN/ACK->ACK.
427 */
428 if (TSTMP_GT(sc->sc_rxttime, tick)) {
429 if (TSTMP_LT(sc->sc_rxttime, sch->sch_nextc))
430 sch->sch_nextc = sc->sc_rxttime;
431 continue;
432 }
379}
380
381/*
382 * Engage/reengage time on bucket row.
383 */
384static void
385syncache_timeout(struct syncache *sc, struct syncache_head *sch, int docallout)
386{

--- 39 unchanged lines hidden (view full) ---

426 * then the RST will be sent by the time the remote
427 * host does the SYN/ACK->ACK.
428 */
429 if (TSTMP_GT(sc->sc_rxttime, tick)) {
430 if (TSTMP_LT(sc->sc_rxttime, sch->sch_nextc))
431 sch->sch_nextc = sc->sc_rxttime;
432 continue;
433 }
433 if (sc->sc_rxmits > tcp_syncache.rexmt_limit) {
434 if (sc->sc_rxmits > V_tcp_syncache.rexmt_limit) {
434 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
435 log(LOG_DEBUG, "%s; %s: Retransmits exhausted, "
436 "giving up and removing syncache entry\n",
437 s, __func__);
438 free(s, M_TCPLOG);
439 }
440 syncache_drop(sc, sch);
435 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
436 log(LOG_DEBUG, "%s; %s: Retransmits exhausted, "
437 "giving up and removing syncache entry\n",
438 s, __func__);
439 free(s, M_TCPLOG);
440 }
441 syncache_drop(sc, sch);
441 tcpstat.tcps_sc_stale++;
442 V_tcpstat.tcps_sc_stale++;
442 continue;
443 }
444 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
445 log(LOG_DEBUG, "%s; %s: Response timeout, "
446 "retransmitting (%u) SYN|ACK\n",
447 s, __func__, sc->sc_rxmits);
448 free(s, M_TCPLOG);
449 }
450
451 (void) syncache_respond(sc);
443 continue;
444 }
445 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
446 log(LOG_DEBUG, "%s; %s: Response timeout, "
447 "retransmitting (%u) SYN|ACK\n",
448 s, __func__, sc->sc_rxmits);
449 free(s, M_TCPLOG);
450 }
451
452 (void) syncache_respond(sc);
452 tcpstat.tcps_sc_retransmitted++;
453 V_tcpstat.tcps_sc_retransmitted++;
453 syncache_timeout(sc, sch, 0);
454 }
455 if (!TAILQ_EMPTY(&(sch)->sch_bucket))
456 callout_reset(&(sch)->sch_timer, (sch)->sch_nextc - tick,
457 syncache_timer, (void *)(sch));
458}
459
460/*
461 * Find an entry in the syncache.
462 * Returns always with locked syncache_head plus a matching entry or NULL.
463 */
464struct syncache *
465syncache_lookup(struct in_conninfo *inc, struct syncache_head **schp)
466{
467 struct syncache *sc;
468 struct syncache_head *sch;
469
470#ifdef INET6
471 if (inc->inc_isipv6) {
454 syncache_timeout(sc, sch, 0);
455 }
456 if (!TAILQ_EMPTY(&(sch)->sch_bucket))
457 callout_reset(&(sch)->sch_timer, (sch)->sch_nextc - tick,
458 syncache_timer, (void *)(sch));
459}
460
461/*
462 * Find an entry in the syncache.
463 * Returns always with locked syncache_head plus a matching entry or NULL.
464 */
465struct syncache *
466syncache_lookup(struct in_conninfo *inc, struct syncache_head **schp)
467{
468 struct syncache *sc;
469 struct syncache_head *sch;
470
471#ifdef INET6
472 if (inc->inc_isipv6) {
472 sch = &tcp_syncache.hashbase[
473 SYNCACHE_HASH6(inc, tcp_syncache.hashmask)];
473 sch = &V_tcp_syncache.hashbase[
474 SYNCACHE_HASH6(inc, V_tcp_syncache.hashmask)];
474 *schp = sch;
475
476 SCH_LOCK(sch);
477
478 /* Circle through bucket row to find matching entry. */
479 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
480 if (ENDPTS6_EQ(&inc->inc_ie, &sc->sc_inc.inc_ie))
481 return (sc);
482 }
483 } else
484#endif
485 {
475 *schp = sch;
476
477 SCH_LOCK(sch);
478
479 /* Circle through bucket row to find matching entry. */
480 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
481 if (ENDPTS6_EQ(&inc->inc_ie, &sc->sc_inc.inc_ie))
482 return (sc);
483 }
484 } else
485#endif
486 {
486 sch = &tcp_syncache.hashbase[
487 SYNCACHE_HASH(inc, tcp_syncache.hashmask)];
487 sch = &V_tcp_syncache.hashbase[
488 SYNCACHE_HASH(inc, V_tcp_syncache.hashmask)];
488 *schp = sch;
489
490 SCH_LOCK(sch);
491
492 /* Circle through bucket row to find matching entry. */
493 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
494#ifdef INET6
495 if (sc->sc_inc.inc_isipv6)

--- 25 unchanged lines hidden (view full) ---

521 /*
522 * Any RST to our SYN|ACK must not carry ACK, SYN or FIN flags.
523 * See RFC 793 page 65, section SEGMENT ARRIVES.
524 */
525 if (th->th_flags & (TH_ACK|TH_SYN|TH_FIN)) {
526 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
527 log(LOG_DEBUG, "%s; %s: Spurious RST with ACK, SYN or "
528 "FIN flag set, segment ignored\n", s, __func__);
489 *schp = sch;
490
491 SCH_LOCK(sch);
492
493 /* Circle through bucket row to find matching entry. */
494 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
495#ifdef INET6
496 if (sc->sc_inc.inc_isipv6)

--- 25 unchanged lines hidden (view full) ---

522 /*
523 * Any RST to our SYN|ACK must not carry ACK, SYN or FIN flags.
524 * See RFC 793 page 65, section SEGMENT ARRIVES.
525 */
526 if (th->th_flags & (TH_ACK|TH_SYN|TH_FIN)) {
527 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
528 log(LOG_DEBUG, "%s; %s: Spurious RST with ACK, SYN or "
529 "FIN flag set, segment ignored\n", s, __func__);
529 tcpstat.tcps_badrst++;
530 V_tcpstat.tcps_badrst++;
530 goto done;
531 }
532
533 /*
534 * No corresponding connection was found in syncache.
535 * If syncookies are enabled and possibly exclusively
536 * used, or we are under memory pressure, a valid RST
537 * may not find a syncache entry. In that case we're
538 * done and no SYN|ACK retransmissions will happen.
539 * Otherwise the the RST was misdirected or spoofed.
540 */
541 if (sc == NULL) {
542 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
543 log(LOG_DEBUG, "%s; %s: Spurious RST without matching "
544 "syncache entry (possibly syncookie only), "
545 "segment ignored\n", s, __func__);
531 goto done;
532 }
533
534 /*
535 * No corresponding connection was found in syncache.
536 * If syncookies are enabled and possibly exclusively
537 * used, or we are under memory pressure, a valid RST
538 * may not find a syncache entry. In that case we're
539 * done and no SYN|ACK retransmissions will happen.
540 * Otherwise the the RST was misdirected or spoofed.
541 */
542 if (sc == NULL) {
543 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
544 log(LOG_DEBUG, "%s; %s: Spurious RST without matching "
545 "syncache entry (possibly syncookie only), "
546 "segment ignored\n", s, __func__);
546 tcpstat.tcps_badrst++;
547 V_tcpstat.tcps_badrst++;
547 goto done;
548 }
549
550 /*
551 * If the RST bit is set, check the sequence number to see
552 * if this is a valid reset segment.
553 * RFC 793 page 37:
554 * In all states except SYN-SENT, all reset (RST) segments

--- 7 unchanged lines hidden (view full) ---

562 */
563 if (SEQ_GEQ(th->th_seq, sc->sc_irs) &&
564 SEQ_LEQ(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
565 syncache_drop(sc, sch);
566 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
567 log(LOG_DEBUG, "%s; %s: Our SYN|ACK was rejected, "
568 "connection attempt aborted by remote endpoint\n",
569 s, __func__);
548 goto done;
549 }
550
551 /*
552 * If the RST bit is set, check the sequence number to see
553 * if this is a valid reset segment.
554 * RFC 793 page 37:
555 * In all states except SYN-SENT, all reset (RST) segments

--- 7 unchanged lines hidden (view full) ---

563 */
564 if (SEQ_GEQ(th->th_seq, sc->sc_irs) &&
565 SEQ_LEQ(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
566 syncache_drop(sc, sch);
567 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
568 log(LOG_DEBUG, "%s; %s: Our SYN|ACK was rejected, "
569 "connection attempt aborted by remote endpoint\n",
570 s, __func__);
570 tcpstat.tcps_sc_reset++;
571 V_tcpstat.tcps_sc_reset++;
571 } else {
572 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
573 log(LOG_DEBUG, "%s; %s: RST with invalid SEQ %u != "
574 "IRS %u (+WND %u), segment ignored\n",
575 s, __func__, th->th_seq, sc->sc_irs, sc->sc_wnd);
572 } else {
573 if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
574 log(LOG_DEBUG, "%s; %s: RST with invalid SEQ %u != "
575 "IRS %u (+WND %u), segment ignored\n",
576 s, __func__, th->th_seq, sc->sc_irs, sc->sc_wnd);
576 tcpstat.tcps_badrst++;
577 V_tcpstat.tcps_badrst++;
577 }
578
579done:
580 if (s != NULL)
581 free(s, M_TCPLOG);
582 SCH_UNLOCK(sch);
583}
584
585void
586syncache_badack(struct in_conninfo *inc)
587{
588 struct syncache *sc;
589 struct syncache_head *sch;
590
591 sc = syncache_lookup(inc, &sch); /* returns locked sch */
592 SCH_LOCK_ASSERT(sch);
593 if (sc != NULL) {
594 syncache_drop(sc, sch);
578 }
579
580done:
581 if (s != NULL)
582 free(s, M_TCPLOG);
583 SCH_UNLOCK(sch);
584}
585
586void
587syncache_badack(struct in_conninfo *inc)
588{
589 struct syncache *sc;
590 struct syncache_head *sch;
591
592 sc = syncache_lookup(inc, &sch); /* returns locked sch */
593 SCH_LOCK_ASSERT(sch);
594 if (sc != NULL) {
595 syncache_drop(sc, sch);
595 tcpstat.tcps_sc_badack++;
596 V_tcpstat.tcps_sc_badack++;
596 }
597 SCH_UNLOCK(sch);
598}
599
600void
601syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
602{
603 struct syncache *sc;

--- 16 unchanged lines hidden (view full) ---

620 *
621 * See tcp_notify().
622 */
623 if ((sc->sc_flags & SCF_UNREACH) == 0 || sc->sc_rxmits < 3 + 1) {
624 sc->sc_flags |= SCF_UNREACH;
625 goto done;
626 }
627 syncache_drop(sc, sch);
597 }
598 SCH_UNLOCK(sch);
599}
600
601void
602syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
603{
604 struct syncache *sc;

--- 16 unchanged lines hidden (view full) ---

621 *
622 * See tcp_notify().
623 */
624 if ((sc->sc_flags & SCF_UNREACH) == 0 || sc->sc_rxmits < 3 + 1) {
625 sc->sc_flags |= SCF_UNREACH;
626 goto done;
627 }
628 syncache_drop(sc, sch);
628 tcpstat.tcps_sc_unreach++;
629 V_tcpstat.tcps_sc_unreach++;
629done:
630 SCH_UNLOCK(sch);
631}
632
633/*
634 * Build a new TCP socket structure from a syncache entry.
635 */
636static struct socket *
637syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
638{
639 struct inpcb *inp = NULL;
640 struct socket *so;
641 struct tcpcb *tp;
642 char *s;
643
630done:
631 SCH_UNLOCK(sch);
632}
633
634/*
635 * Build a new TCP socket structure from a syncache entry.
636 */
637static struct socket *
638syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
639{
640 struct inpcb *inp = NULL;
641 struct socket *so;
642 struct tcpcb *tp;
643 char *s;
644
644 INP_INFO_WLOCK_ASSERT(&tcbinfo);
645 INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
645
646 /*
647 * Ok, create the full blown connection, and set things up
648 * as they would have been set up if we had created the
649 * connection when the SYN arrived. If we can't create
650 * the connection, abort it.
651 */
652 so = sonewconn(lso, SS_ISCONNECTED);
653 if (so == NULL) {
654 /*
655 * Drop the connection; we will either send a RST or
656 * have the peer retransmit its SYN again after its
657 * RTO and try again.
658 */
646
647 /*
648 * Ok, create the full blown connection, and set things up
649 * as they would have been set up if we had created the
650 * connection when the SYN arrived. If we can't create
651 * the connection, abort it.
652 */
653 so = sonewconn(lso, SS_ISCONNECTED);
654 if (so == NULL) {
655 /*
656 * Drop the connection; we will either send a RST or
657 * have the peer retransmit its SYN again after its
658 * RTO and try again.
659 */
659 tcpstat.tcps_listendrop++;
660 V_tcpstat.tcps_listendrop++;
660 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
661 log(LOG_DEBUG, "%s; %s: Socket create failed "
662 "due to limits or memory shortage\n",
663 s, __func__);
664 free(s, M_TCPLOG);
665 }
666 goto abort2;
667 }

--- 153 unchanged lines hidden (view full) ---

821 * If the SYN,ACK was retransmitted, reset cwnd to 1 segment.
822 */
823 if (sc->sc_rxmits)
824 tp->snd_cwnd = tp->t_maxseg;
825 tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
826
827 INP_WUNLOCK(inp);
828
661 if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) {
662 log(LOG_DEBUG, "%s; %s: Socket create failed "
663 "due to limits or memory shortage\n",
664 s, __func__);
665 free(s, M_TCPLOG);
666 }
667 goto abort2;
668 }

--- 153 unchanged lines hidden (view full) ---

822 * If the SYN,ACK was retransmitted, reset cwnd to 1 segment.
823 */
824 if (sc->sc_rxmits)
825 tp->snd_cwnd = tp->t_maxseg;
826 tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
827
828 INP_WUNLOCK(inp);
829
829 tcpstat.tcps_accepts++;
830 V_tcpstat.tcps_accepts++;
830 return (so);
831
832abort:
833 INP_WUNLOCK(inp);
834abort2:
835 if (so != NULL)
836 soabort(so);
837 return (NULL);

--- 14 unchanged lines hidden (view full) ---

852 struct syncache_head *sch;
853 struct syncache scs;
854 char *s;
855
856 /*
857 * Global TCP locks are held because we manipulate the PCB lists
858 * and create a new socket.
859 */
831 return (so);
832
833abort:
834 INP_WUNLOCK(inp);
835abort2:
836 if (so != NULL)
837 soabort(so);
838 return (NULL);

--- 14 unchanged lines hidden (view full) ---

853 struct syncache_head *sch;
854 struct syncache scs;
855 char *s;
856
857 /*
858 * Global TCP locks are held because we manipulate the PCB lists
859 * and create a new socket.
860 */
860 INP_INFO_WLOCK_ASSERT(&tcbinfo);
861 INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
861 KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK,
862 ("%s: can handle only ACK", __func__));
863
864 sc = syncache_lookup(inc, &sch); /* returns locked sch */
865 SCH_LOCK_ASSERT(sch);
866 if (sc == NULL) {
867 /*
868 * There is no syncache entry, so see if this ACK is

--- 21 unchanged lines hidden (view full) ---

890 "SYNCOOKIE authentication, segment rejected "
891 "(probably spoofed)\n", s, __func__);
892 goto failed;
893 }
894 } else {
895 /* Pull out the entry to unlock the bucket row. */
896 TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
897 sch->sch_length--;
862 KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK,
863 ("%s: can handle only ACK", __func__));
864
865 sc = syncache_lookup(inc, &sch); /* returns locked sch */
866 SCH_LOCK_ASSERT(sch);
867 if (sc == NULL) {
868 /*
869 * There is no syncache entry, so see if this ACK is

--- 21 unchanged lines hidden (view full) ---

891 "SYNCOOKIE authentication, segment rejected "
892 "(probably spoofed)\n", s, __func__);
893 goto failed;
894 }
895 } else {
896 /* Pull out the entry to unlock the bucket row. */
897 TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
898 sch->sch_length--;
898 tcp_syncache.cache_count--;
899 V_tcp_syncache.cache_count--;
899 SCH_UNLOCK(sch);
900 }
901
902 /*
903 * Segment validation:
904 * ACK must match our initial sequence number + 1 (the SYN|ACK).
905 */
906 if (th->th_ack != sc->sc_iss + 1 && !TOEPCB_ISSET(sc)) {

--- 33 unchanged lines hidden (view full) ---

940 "segment rejected\n",
941 s, __func__, to->to_tsecr, sc->sc_ts);
942 goto failed;
943 }
944
945 *lsop = syncache_socket(sc, *lsop, m);
946
947 if (*lsop == NULL)
900 SCH_UNLOCK(sch);
901 }
902
903 /*
904 * Segment validation:
905 * ACK must match our initial sequence number + 1 (the SYN|ACK).
906 */
907 if (th->th_ack != sc->sc_iss + 1 && !TOEPCB_ISSET(sc)) {

--- 33 unchanged lines hidden (view full) ---

941 "segment rejected\n",
942 s, __func__, to->to_tsecr, sc->sc_ts);
943 goto failed;
944 }
945
946 *lsop = syncache_socket(sc, *lsop, m);
947
948 if (*lsop == NULL)
948 tcpstat.tcps_sc_aborted++;
949 V_tcpstat.tcps_sc_aborted++;
949 else
950 else
950 tcpstat.tcps_sc_completed++;
951 V_tcpstat.tcps_sc_completed++;
951
952/* how do we find the inp for the new socket? */
953 if (sc != &scs)
954 syncache_free(sc);
955 return (1);
956failed:
957 if (sc != NULL && sc != &scs)
958 syncache_free(sc);

--- 4 unchanged lines hidden (view full) ---

963}
964
965int
966tcp_offload_syncache_expand(struct in_conninfo *inc, struct tcpopt *to,
967 struct tcphdr *th, struct socket **lsop, struct mbuf *m)
968{
969 int rc;
970
952
953/* how do we find the inp for the new socket? */
954 if (sc != &scs)
955 syncache_free(sc);
956 return (1);
957failed:
958 if (sc != NULL && sc != &scs)
959 syncache_free(sc);

--- 4 unchanged lines hidden (view full) ---

964}
965
966int
967tcp_offload_syncache_expand(struct in_conninfo *inc, struct tcpopt *to,
968 struct tcphdr *th, struct socket **lsop, struct mbuf *m)
969{
970 int rc;
971
971 INP_INFO_WLOCK(&tcbinfo);
972 INP_INFO_WLOCK(&V_tcbinfo);
972 rc = syncache_expand(inc, to, th, lsop, m);
973 rc = syncache_expand(inc, to, th, lsop, m);
973 INP_INFO_WUNLOCK(&tcbinfo);
974 INP_INFO_WUNLOCK(&V_tcbinfo);
974
975 return (rc);
976}
977
978/*
979 * Given a LISTEN socket and an inbound SYN request, add
980 * this to the syn cache, and send back a segment:
981 * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>

--- 22 unchanged lines hidden (view full) ---

1004#ifdef INET6
1005 int autoflowlabel = 0;
1006#endif
1007#ifdef MAC
1008 struct label *maclabel;
1009#endif
1010 struct syncache scs;
1011
975
976 return (rc);
977}
978
979/*
980 * Given a LISTEN socket and an inbound SYN request, add
981 * this to the syn cache, and send back a segment:
982 * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>

--- 22 unchanged lines hidden (view full) ---

1005#ifdef INET6
1006 int autoflowlabel = 0;
1007#endif
1008#ifdef MAC
1009 struct label *maclabel;
1010#endif
1011 struct syncache scs;
1012
1012 INP_INFO_WLOCK_ASSERT(&tcbinfo);
1013 INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
1013 INP_WLOCK_ASSERT(inp); /* listen socket */
1014 KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN,
1015 ("%s: unexpected tcp flags", __func__));
1016
1017 /*
1018 * Combine all so/tp operations very early to drop the INP lock as
1019 * soon as possible.
1020 */

--- 12 unchanged lines hidden (view full) ---

1033 noopt = (tp->t_flags & TF_NOOPT);
1034
1035 so = NULL;
1036 tp = NULL;
1037
1038#ifdef MAC
1039 if (mac_syncache_init(&maclabel) != 0) {
1040 INP_WUNLOCK(inp);
1014 INP_WLOCK_ASSERT(inp); /* listen socket */
1015 KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN,
1016 ("%s: unexpected tcp flags", __func__));
1017
1018 /*
1019 * Combine all so/tp operations very early to drop the INP lock as
1020 * soon as possible.
1021 */

--- 12 unchanged lines hidden (view full) ---

1034 noopt = (tp->t_flags & TF_NOOPT);
1035
1036 so = NULL;
1037 tp = NULL;
1038
1039#ifdef MAC
1040 if (mac_syncache_init(&maclabel) != 0) {
1041 INP_WUNLOCK(inp);
1041 INP_INFO_WUNLOCK(&tcbinfo);
1042 INP_INFO_WUNLOCK(&V_tcbinfo);
1042 goto done;
1043 } else
1044 mac_syncache_create(maclabel, inp);
1045#endif
1046 INP_WUNLOCK(inp);
1043 goto done;
1044 } else
1045 mac_syncache_create(maclabel, inp);
1046#endif
1047 INP_WUNLOCK(inp);
1047 INP_INFO_WUNLOCK(&tcbinfo);
1048 INP_INFO_WUNLOCK(&V_tcbinfo);
1048
1049 /*
1050 * Remember the IP options, if any.
1051 */
1052#ifdef INET6
1053 if (!inc->inc_isipv6)
1054#endif
1055 ipopts = (m) ? ip_srcroute(m) : NULL;

--- 13 unchanged lines hidden (view full) ---

1069 sc = syncache_lookup(inc, &sch); /* returns locked entry */
1070 SCH_LOCK_ASSERT(sch);
1071 if (sc != NULL) {
1072#ifndef TCP_OFFLOAD_DISABLE
1073 if (sc->sc_tu)
1074 sc->sc_tu->tu_syncache_event(TOE_SC_ENTRY_PRESENT,
1075 sc->sc_toepcb);
1076#endif
1049
1050 /*
1051 * Remember the IP options, if any.
1052 */
1053#ifdef INET6
1054 if (!inc->inc_isipv6)
1055#endif
1056 ipopts = (m) ? ip_srcroute(m) : NULL;

--- 13 unchanged lines hidden (view full) ---

1070 sc = syncache_lookup(inc, &sch); /* returns locked entry */
1071 SCH_LOCK_ASSERT(sch);
1072 if (sc != NULL) {
1073#ifndef TCP_OFFLOAD_DISABLE
1074 if (sc->sc_tu)
1075 sc->sc_tu->tu_syncache_event(TOE_SC_ENTRY_PRESENT,
1076 sc->sc_toepcb);
1077#endif
1077 tcpstat.tcps_sc_dupsyn++;
1078 V_tcpstat.tcps_sc_dupsyn++;
1078 if (ipopts) {
1079 /*
1080 * If we were remembering a previous source route,
1081 * forget it and use the new one we've been given.
1082 */
1083 if (sc->sc_ipopts)
1084 (void) m_free(sc->sc_ipopts);
1085 sc->sc_ipopts = ipopts;

--- 20 unchanged lines hidden (view full) ---

1106 log(LOG_DEBUG, "%s; %s: Received duplicate SYN, "
1107 "resetting timer and retransmitting SYN|ACK\n",
1108 s, __func__);
1109 free(s, M_TCPLOG);
1110 }
1111 if (!TOEPCB_ISSET(sc) && syncache_respond(sc) == 0) {
1112 sc->sc_rxmits = 0;
1113 syncache_timeout(sc, sch, 1);
1079 if (ipopts) {
1080 /*
1081 * If we were remembering a previous source route,
1082 * forget it and use the new one we've been given.
1083 */
1084 if (sc->sc_ipopts)
1085 (void) m_free(sc->sc_ipopts);
1086 sc->sc_ipopts = ipopts;

--- 20 unchanged lines hidden (view full) ---

1107 log(LOG_DEBUG, "%s; %s: Received duplicate SYN, "
1108 "resetting timer and retransmitting SYN|ACK\n",
1109 s, __func__);
1110 free(s, M_TCPLOG);
1111 }
1112 if (!TOEPCB_ISSET(sc) && syncache_respond(sc) == 0) {
1113 sc->sc_rxmits = 0;
1114 syncache_timeout(sc, sch, 1);
1114 tcpstat.tcps_sndacks++;
1115 tcpstat.tcps_sndtotal++;
1115 V_tcpstat.tcps_sndacks++;
1116 V_tcpstat.tcps_sndtotal++;
1116 }
1117 SCH_UNLOCK(sch);
1118 goto done;
1119 }
1120
1117 }
1118 SCH_UNLOCK(sch);
1119 goto done;
1120 }
1121
1121 sc = uma_zalloc(tcp_syncache.zone, M_NOWAIT | M_ZERO);
1122 sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO);
1122 if (sc == NULL) {
1123 /*
1124 * The zone allocator couldn't provide more entries.
1125 * Treat this as if the cache was full; drop the oldest
1126 * entry and insert the new one.
1127 */
1123 if (sc == NULL) {
1124 /*
1125 * The zone allocator couldn't provide more entries.
1126 * Treat this as if the cache was full; drop the oldest
1127 * entry and insert the new one.
1128 */
1128 tcpstat.tcps_sc_zonefail++;
1129 V_tcpstat.tcps_sc_zonefail++;
1129 if ((sc = TAILQ_LAST(&sch->sch_bucket, sch_head)) != NULL)
1130 syncache_drop(sc, sch);
1130 if ((sc = TAILQ_LAST(&sch->sch_bucket, sch_head)) != NULL)
1131 syncache_drop(sc, sch);
1131 sc = uma_zalloc(tcp_syncache.zone, M_NOWAIT | M_ZERO);
1132 sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO);
1132 if (sc == NULL) {
1133 if (tcp_syncookies) {
1134 bzero(&scs, sizeof(scs));
1135 sc = &scs;
1136 } else {
1137 SCH_UNLOCK(sch);
1138 if (ipopts)
1139 (void) m_free(ipopts);

--- 30 unchanged lines hidden (view full) ---

1170 /*
1171 * Initial receive window: clip sbspace to [0 .. TCP_MAXWIN].
1172 * win was derived from socket earlier in the function.
1173 */
1174 win = imax(win, 0);
1175 win = imin(win, TCP_MAXWIN);
1176 sc->sc_wnd = win;
1177
1133 if (sc == NULL) {
1134 if (tcp_syncookies) {
1135 bzero(&scs, sizeof(scs));
1136 sc = &scs;
1137 } else {
1138 SCH_UNLOCK(sch);
1139 if (ipopts)
1140 (void) m_free(ipopts);

--- 30 unchanged lines hidden (view full) ---

1171 /*
1172 * Initial receive window: clip sbspace to [0 .. TCP_MAXWIN].
1173 * win was derived from socket earlier in the function.
1174 */
1175 win = imax(win, 0);
1176 win = imin(win, TCP_MAXWIN);
1177 sc->sc_wnd = win;
1178
1178 if (tcp_do_rfc1323) {
1179 if (V_tcp_do_rfc1323) {
1179 /*
1180 * A timestamp received in a SYN makes
1181 * it ok to send timestamp requests and replies.
1182 */
1183 if (to->to_flags & TOF_TS) {
1184 sc->sc_tsreflect = to->to_tsval;
1185 sc->sc_ts = ticks;
1186 sc->sc_flags |= SCF_TIMESTAMP;

--- 42 unchanged lines hidden (view full) ---

1229 sc->sc_flags |= SCF_SIGNATURE;
1230#endif
1231 if (to->to_flags & TOF_SACKPERM)
1232 sc->sc_flags |= SCF_SACK;
1233 if (to->to_flags & TOF_MSS)
1234 sc->sc_peer_mss = to->to_mss; /* peer mss may be zero */
1235 if (noopt)
1236 sc->sc_flags |= SCF_NOOPT;
1180 /*
1181 * A timestamp received in a SYN makes
1182 * it ok to send timestamp requests and replies.
1183 */
1184 if (to->to_flags & TOF_TS) {
1185 sc->sc_tsreflect = to->to_tsval;
1186 sc->sc_ts = ticks;
1187 sc->sc_flags |= SCF_TIMESTAMP;

--- 42 unchanged lines hidden (view full) ---

1230 sc->sc_flags |= SCF_SIGNATURE;
1231#endif
1232 if (to->to_flags & TOF_SACKPERM)
1233 sc->sc_flags |= SCF_SACK;
1234 if (to->to_flags & TOF_MSS)
1235 sc->sc_peer_mss = to->to_mss; /* peer mss may be zero */
1236 if (noopt)
1237 sc->sc_flags |= SCF_NOOPT;
1237 if ((th->th_flags & (TH_ECE|TH_CWR)) && tcp_do_ecn)
1238 if ((th->th_flags & (TH_ECE|TH_CWR)) && V_tcp_do_ecn)
1238 sc->sc_flags |= SCF_ECN;
1239
1240 if (tcp_syncookies) {
1241 syncookie_generate(sch, sc, &flowtmp);
1242#ifdef INET6
1243 if (autoflowlabel)
1244 sc->sc_flowlabel = flowtmp;
1245#endif

--- 9 unchanged lines hidden (view full) ---

1255 /*
1256 * Do a standard 3-way handshake.
1257 */
1258 if (TOEPCB_ISSET(sc) || syncache_respond(sc) == 0) {
1259 if (tcp_syncookies && tcp_syncookiesonly && sc != &scs)
1260 syncache_free(sc);
1261 else if (sc != &scs)
1262 syncache_insert(sc, sch); /* locks and unlocks sch */
1239 sc->sc_flags |= SCF_ECN;
1240
1241 if (tcp_syncookies) {
1242 syncookie_generate(sch, sc, &flowtmp);
1243#ifdef INET6
1244 if (autoflowlabel)
1245 sc->sc_flowlabel = flowtmp;
1246#endif

--- 9 unchanged lines hidden (view full) ---

1256 /*
1257 * Do a standard 3-way handshake.
1258 */
1259 if (TOEPCB_ISSET(sc) || syncache_respond(sc) == 0) {
1260 if (tcp_syncookies && tcp_syncookiesonly && sc != &scs)
1261 syncache_free(sc);
1262 else if (sc != &scs)
1263 syncache_insert(sc, sch); /* locks and unlocks sch */
1263 tcpstat.tcps_sndacks++;
1264 tcpstat.tcps_sndtotal++;
1264 V_tcpstat.tcps_sndacks++;
1265 V_tcpstat.tcps_sndtotal++;
1265 } else {
1266 if (sc != &scs)
1267 syncache_free(sc);
1266 } else {
1267 if (sc != &scs)
1268 syncache_free(sc);
1268 tcpstat.tcps_sc_dropped++;
1269 V_tcpstat.tcps_sc_dropped++;
1269 }
1270
1271done:
1272#ifdef MAC
1273 if (sc == &scs)
1274 mac_syncache_destroy(&maclabel);
1275#endif
1276 if (m) {

--- 22 unchanged lines hidden (view full) ---

1299 (sc->sc_inc.inc_isipv6) ? sizeof(struct ip6_hdr) :
1300#endif
1301 sizeof(struct ip);
1302 tlen = hlen + sizeof(struct tcphdr);
1303
1304 /* Determine MSS we advertize to other end of connection. */
1305 mssopt = tcp_mssopt(&sc->sc_inc);
1306 if (sc->sc_peer_mss)
1270 }
1271
1272done:
1273#ifdef MAC
1274 if (sc == &scs)
1275 mac_syncache_destroy(&maclabel);
1276#endif
1277 if (m) {

--- 22 unchanged lines hidden (view full) ---

1300 (sc->sc_inc.inc_isipv6) ? sizeof(struct ip6_hdr) :
1301#endif
1302 sizeof(struct ip);
1303 tlen = hlen + sizeof(struct tcphdr);
1304
1305 /* Determine MSS we advertize to other end of connection. */
1306 mssopt = tcp_mssopt(&sc->sc_inc);
1307 if (sc->sc_peer_mss)
1307 mssopt = max( min(sc->sc_peer_mss, mssopt), tcp_minmss);
1308 mssopt = max( min(sc->sc_peer_mss, mssopt), V_tcp_minmss);
1308
1309 /* XXX: Assume that the entire packet will fit in a header mbuf. */
1310 KASSERT(max_linkhdr + tlen + TCP_MAXOLEN <= MHLEN,
1311 ("syncache: mbuf too small"));
1312
1313 /* Create the IP+TCP header from scratch. */
1314 m = m_gethdr(M_DONTWAIT, MT_DATA);
1315 if (m == NULL)

--- 37 unchanged lines hidden (view full) ---

1353
1354 /*
1355 * See if we should do MTU discovery. Route lookups are
1356 * expensive, so we will only unset the DF bit if:
1357 *
1358 * 1) path_mtu_discovery is disabled
1359 * 2) the SCF_UNREACH flag has been set
1360 */
1309
1310 /* XXX: Assume that the entire packet will fit in a header mbuf. */
1311 KASSERT(max_linkhdr + tlen + TCP_MAXOLEN <= MHLEN,
1312 ("syncache: mbuf too small"));
1313
1314 /* Create the IP+TCP header from scratch. */
1315 m = m_gethdr(M_DONTWAIT, MT_DATA);
1316 if (m == NULL)

--- 37 unchanged lines hidden (view full) ---

1354
1355 /*
1356 * See if we should do MTU discovery. Route lookups are
1357 * expensive, so we will only unset the DF bit if:
1358 *
1359 * 1) path_mtu_discovery is disabled
1360 * 2) the SCF_UNREACH flag has been set
1361 */
1361 if (path_mtu_discovery && ((sc->sc_flags & SCF_UNREACH) == 0))
1362 if (V_path_mtu_discovery && ((sc->sc_flags & SCF_UNREACH) == 0))
1362 ip->ip_off |= IP_DF;
1363
1364 th = (struct tcphdr *)(ip + 1);
1365 }
1366 th->th_sport = sc->sc_inc.inc_lport;
1367 th->th_dport = sc->sc_inc.inc_fport;
1368
1369 th->th_seq = htonl(sc->sc_iss);
1370 th->th_ack = htonl(sc->sc_irs + 1);
1371 th->th_off = sizeof(struct tcphdr) >> 2;
1372 th->th_x2 = 0;
1373 th->th_flags = TH_SYN|TH_ACK;
1374 th->th_win = htons(sc->sc_wnd);
1375 th->th_urp = 0;
1376
1377 if (sc->sc_flags & SCF_ECN) {
1378 th->th_flags |= TH_ECE;
1363 ip->ip_off |= IP_DF;
1364
1365 th = (struct tcphdr *)(ip + 1);
1366 }
1367 th->th_sport = sc->sc_inc.inc_lport;
1368 th->th_dport = sc->sc_inc.inc_fport;
1369
1370 th->th_seq = htonl(sc->sc_iss);
1371 th->th_ack = htonl(sc->sc_irs + 1);
1372 th->th_off = sizeof(struct tcphdr) >> 2;
1373 th->th_x2 = 0;
1374 th->th_flags = TH_SYN|TH_ACK;
1375 th->th_win = htons(sc->sc_wnd);
1376 th->th_urp = 0;
1377
1378 if (sc->sc_flags & SCF_ECN) {
1379 th->th_flags |= TH_ECE;
1379 tcpstat.tcps_ecn_shs++;
1380 V_tcpstat.tcps_ecn_shs++;
1380 }
1381
1382 /* Tack on the TCP options. */
1383 if ((sc->sc_flags & SCF_NOOPT) == 0) {
1384 to.to_flags = 0;
1385
1386 to.to_mss = mssopt;
1387 to.to_flags = TOF_MSS;

--- 61 unchanged lines hidden (view full) ---

1449}
1450
1451void
1452tcp_offload_syncache_add(struct in_conninfo *inc, struct tcpopt *to,
1453 struct tcphdr *th, struct inpcb *inp, struct socket **lsop,
1454 struct toe_usrreqs *tu, void *toepcb)
1455{
1456
1381 }
1382
1383 /* Tack on the TCP options. */
1384 if ((sc->sc_flags & SCF_NOOPT) == 0) {
1385 to.to_flags = 0;
1386
1387 to.to_mss = mssopt;
1388 to.to_flags = TOF_MSS;

--- 61 unchanged lines hidden (view full) ---

1450}
1451
1452void
1453tcp_offload_syncache_add(struct in_conninfo *inc, struct tcpopt *to,
1454 struct tcphdr *th, struct inpcb *inp, struct socket **lsop,
1455 struct toe_usrreqs *tu, void *toepcb)
1456{
1457
1457 INP_INFO_WLOCK(&tcbinfo);
1458 INP_INFO_WLOCK(&V_tcbinfo);
1458 INP_WLOCK(inp);
1459 _syncache_add(inc, to, th, inp, lsop, NULL, tu, toepcb);
1460}
1461
1462/*
1463 * The purpose of SYN cookies is to avoid keeping track of all SYN's we
1464 * receive and to be able to handle SYN floods from bogus source addresses
1465 * (where we will never receive any reply). SYN floods try to exhaust all

--- 97 unchanged lines hidden (view full) ---

1563 secbits[i] = arc4random();
1564 sch->sch_reseed = time_uptime + SYNCOOKIE_LIFETIME;
1565 }
1566
1567 /* Secret rotation offset. */
1568 off = sc->sc_iss & 0x7; /* iss was randomized before */
1569
1570 /* Maximum segment size calculation. */
1459 INP_WLOCK(inp);
1460 _syncache_add(inc, to, th, inp, lsop, NULL, tu, toepcb);
1461}
1462
1463/*
1464 * The purpose of SYN cookies is to avoid keeping track of all SYN's we
1465 * receive and to be able to handle SYN floods from bogus source addresses
1466 * (where we will never receive any reply). SYN floods try to exhaust all

--- 97 unchanged lines hidden (view full) ---

1564 secbits[i] = arc4random();
1565 sch->sch_reseed = time_uptime + SYNCOOKIE_LIFETIME;
1566 }
1567
1568 /* Secret rotation offset. */
1569 off = sc->sc_iss & 0x7; /* iss was randomized before */
1570
1571 /* Maximum segment size calculation. */
1571 pmss = max( min(sc->sc_peer_mss, tcp_mssopt(&sc->sc_inc)), tcp_minmss);
1572 pmss = max( min(sc->sc_peer_mss, tcp_mssopt(&sc->sc_inc)), V_tcp_minmss);
1572 for (mss = sizeof(tcp_sc_msstab) / sizeof(int) - 1; mss > 0; mss--)
1573 if (tcp_sc_msstab[mss] <= pmss)
1574 break;
1575
1576 /* Fold parameters and MD5 digest into the ISN we will send. */
1577 data = sch->sch_oddeven;/* odd or even secret, 1 bit */
1578 data |= off << 1; /* secret offset, derived from iss, 3 bits */
1579 data |= mss << 4; /* mss, 3 bits */

--- 21 unchanged lines hidden (view full) ---

1601 data |= sc->sc_requested_s_scale << 2; /* SWIN scale, 4 bits */
1602 data |= sc->sc_requested_r_scale << 6; /* RWIN scale, 4 bits */
1603 data |= md5_buffer[2] << 10; /* more digest bits */
1604 data ^= md5_buffer[3];
1605 sc->sc_ts = data;
1606 sc->sc_tsoff = data - ticks; /* after XOR */
1607 }
1608
1573 for (mss = sizeof(tcp_sc_msstab) / sizeof(int) - 1; mss > 0; mss--)
1574 if (tcp_sc_msstab[mss] <= pmss)
1575 break;
1576
1577 /* Fold parameters and MD5 digest into the ISN we will send. */
1578 data = sch->sch_oddeven;/* odd or even secret, 1 bit */
1579 data |= off << 1; /* secret offset, derived from iss, 3 bits */
1580 data |= mss << 4; /* mss, 3 bits */

--- 21 unchanged lines hidden (view full) ---

1602 data |= sc->sc_requested_s_scale << 2; /* SWIN scale, 4 bits */
1603 data |= sc->sc_requested_r_scale << 6; /* RWIN scale, 4 bits */
1604 data |= md5_buffer[2] << 10; /* more digest bits */
1605 data ^= md5_buffer[3];
1606 sc->sc_ts = data;
1607 sc->sc_tsoff = data - ticks; /* after XOR */
1608 }
1609
1609 tcpstat.tcps_sc_sendcookie++;
1610 V_tcpstat.tcps_sc_sendcookie++;
1610 return;
1611}
1612
1613static struct syncache *
1614syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
1615 struct syncache *sc, struct tcpopt *to, struct tcphdr *th,
1616 struct socket *so)
1617{

--- 86 unchanged lines hidden (view full) ---

1704 wnd = sbspace(&so->so_rcv);
1705 wnd = imax(wnd, 0);
1706 wnd = imin(wnd, TCP_MAXWIN);
1707 sc->sc_wnd = wnd;
1708
1709 sc->sc_rxmits = 0;
1710 sc->sc_peer_mss = tcp_sc_msstab[mss];
1711
1611 return;
1612}
1613
1614static struct syncache *
1615syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
1616 struct syncache *sc, struct tcpopt *to, struct tcphdr *th,
1617 struct socket *so)
1618{

--- 86 unchanged lines hidden (view full) ---

1705 wnd = sbspace(&so->so_rcv);
1706 wnd = imax(wnd, 0);
1707 wnd = imin(wnd, TCP_MAXWIN);
1708 sc->sc_wnd = wnd;
1709
1710 sc->sc_rxmits = 0;
1711 sc->sc_peer_mss = tcp_sc_msstab[mss];
1712
1712 tcpstat.tcps_sc_recvcookie++;
1713 V_tcpstat.tcps_sc_recvcookie++;
1713 return (sc);
1714}
1715
1716/*
1717 * Returns the current number of syncache entries. This number
1718 * will probably change before you get around to calling
1719 * syncache_pcblist.
1720 */
1721
1722int
1723syncache_pcbcount(void)
1724{
1725 struct syncache_head *sch;
1726 int count, i;
1727
1714 return (sc);
1715}
1716
1717/*
1718 * Returns the current number of syncache entries. This number
1719 * will probably change before you get around to calling
1720 * syncache_pcblist.
1721 */
1722
1723int
1724syncache_pcbcount(void)
1725{
1726 struct syncache_head *sch;
1727 int count, i;
1728
1728 for (count = 0, i = 0; i < tcp_syncache.hashsize; i++) {
1729 for (count = 0, i = 0; i < V_tcp_syncache.hashsize; i++) {
1729 /* No need to lock for a read. */
1730 /* No need to lock for a read. */
1730 sch = &tcp_syncache.hashbase[i];
1731 sch = &V_tcp_syncache.hashbase[i];
1731 count += sch->sch_length;
1732 }
1733 return count;
1734}
1735
1736/*
1737 * Exports the syncache entries to userland so that netstat can display
1738 * them alongside the other sockets. This function is intended to be

--- 6 unchanged lines hidden (view full) ---

1745int
1746syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported)
1747{
1748 struct xtcpcb xt;
1749 struct syncache *sc;
1750 struct syncache_head *sch;
1751 int count, error, i;
1752
1732 count += sch->sch_length;
1733 }
1734 return count;
1735}
1736
1737/*
1738 * Exports the syncache entries to userland so that netstat can display
1739 * them alongside the other sockets. This function is intended to be

--- 6 unchanged lines hidden (view full) ---

1746int
1747syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported)
1748{
1749 struct xtcpcb xt;
1750 struct syncache *sc;
1751 struct syncache_head *sch;
1752 int count, error, i;
1753
1753 for (count = 0, error = 0, i = 0; i < tcp_syncache.hashsize; i++) {
1754 sch = &tcp_syncache.hashbase[i];
1754 for (count = 0, error = 0, i = 0; i < V_tcp_syncache.hashsize; i++) {
1755 sch = &V_tcp_syncache.hashbase[i];
1755 SCH_LOCK(sch);
1756 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
1757 if (count >= max_pcbs) {
1758 SCH_UNLOCK(sch);
1759 goto exit;
1760 }
1761 bzero(&xt, sizeof(xt));
1762 xt.xt_len = sizeof(xt);

--- 24 unchanged lines hidden ---
1756 SCH_LOCK(sch);
1757 TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) {
1758 if (count >= max_pcbs) {
1759 SCH_UNLOCK(sch);
1760 goto exit;
1761 }
1762 bzero(&xt, sizeof(xt));
1763 xt.xt_len = sizeof(xt);

--- 24 unchanged lines hidden ---