📄 sctp_hash.c
字号:
int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int rem = (high - low) + 1; seldom(); snum = sctp_port_rover; if ( snum > high || snum < low ) { rare(); snum = low; } /* find a fresh, completely unused port number */ for ( ; rem > 0; snum++, rem-- ) { if ( snum > high || snum < low ) { rare(); snum = low; } sport = htons(snum); if ( !(sb = sctp_bhash[sctp_bhashfn(sport)]) ) break; for ( ; sb; sb = sb->bnext ) if ( sb->sport == sport ) { seldom(); break; } if ( sb ) break; } if ( rem <= 0 || sb ) { rare(); return(0); } sctp_port_rover = snum; usual(sport); return(sport);}/* * ========================================================================= * * LOOKUP Functions * * ========================================================================= * * A fast caching hashing lookup function for SCTP. * * IMPLEMENTATION NOTES:- All but a few SCTP messages carry our Verification * Tag. If the message requires our Verification Tag and we cannot lookup * the stream on the Verification Tag we treat the packet similar to an OOTB * packet. The only restriction that this approach imposes is in the * selection of our Verification Tag, which cannot be identical to any other * Verification Tag which we have chosen so far. We, therefore, check the * Verification Tag selected at initialization against the cache for * uniqueness. This also allows us to acquire the Verification Tag to * minimize collisions on the hash table. This allows us to simplify the * hashing function because we are guaranteeing equal hash coverage using * selection. *//* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP LISTEN - LISTEN hash (sport) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * Listener stream lookup with wildcards. This will find any bound listener * stream from the destination address, destination port and device index. * This is only for INIT and COOKIE ECHO. */static sctp_t *sctp_lookup_listen(uint16_t dport, uint32_t daddr){ sctp_t *sp, *result = NULL; int hiscore = 0; for ( sp = sctp_lhash[sctp_lhashfn(dport)]; sp; sp = sp->next ) { int score = 0; if ( sp->sport ) { if ( sp->sport != dport ) continue; score++; } if ( sp->saddr ) { if ( !sctp_find_saddr(sp, daddr) ) continue; score++; } if ( score == 2 ) { result = sp; break; } if ( score > hiscore ) { hiscore = score; result = sp; } } usual(result); return result;}/* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP - TCB hash (port pair) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * We do the hard match here, because we don't have valid v_tags or p_tags. * We don't have the information anyways. We are just looking for an * established stream which can accept the packet based on port numbers and * source and destination addresses. This is used for INIT and exceptional * COOKIE ECHO cases as well as ICMP lookups for failed sent INIT messages. * */#define sctp_match_tcb(__sp, __saddr, __daddr, __sport, __dport) \ ( ((__sport) == (__sp)->sport) && \ ((__dport) == (__sp)->dport) && \ (sctp_find_saddr((__sp),(__saddr))) && \ (sctp_find_daddr((__sp),(__daddr))) )sctp_t *sctp_lookup_tcb(uint16_t sport, uint16_t dport, uint32_t saddr, uint32_t daddr){ sctp_t *sp; for ( sp = sctp_thash[sctp_thashfn(sport, dport)]; sp; sp = sp->tnext ) if ( sctp_match_tcb(sp, saddr, daddr, sport, dport) ) break; return sp;}/* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP PTAG - Peer hash (peer tag) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * We can either match fast and loose or slow and sure. We have a peer tag * which is validation enough without walking the address lists most of the * time. The INIT and COOKIE ECHO stuff needs it for checking peer tags and * peer tie tags. ICMP needs this for looking up all packets which were * returned that we sent out with the peer's tag (excepts INIT which has no * tag, we use TCB ICMP lookup for that). ICMP lookups match with reversed * source and destination addresses. */#ifndef SCTP_SLOW_VERIFICATION#define sctp_match_ptag(__sp, __saddr, __daddr, __p_tag, __sport, __dport) \ ( ((__p_tag) == (__sp)->p_tag) && \ ((__sport) == (__sp)->sport) && \ ((__dport) == (__sp)->dport) )#else#define sctp_match_ptag(__sp, __saddr, __daddr, __p_tag, __sport, __dport) \ ( ((__p_tag) == (__sp)->p_tag) && \ ((__sport) == (__sp)->sport) && \ ((__dport) == (__sp)->dport) && \ (sctp_find_saddr((__sp),(__saddr))) && \ (sctp_find_daddr((__sp),(__daddr))) )#endifsctp_t *sctp_lookup_ptag(uint32_t p_tag, uint16_t sport, uint16_t dport, uint32_t saddr, uint16_t daddr){ sctp_t *sp; (void)saddr; (void)daddr; for ( sp = sctp_phash[sctp_phashfn(p_tag)]; sp; sp = sp->pnext ) if ( sctp_match_ptag(sp, saddr, daddr, p_tag, sport, dport) ) break; return sp;}/* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP VTAG - Established hash (local tag) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * This is the main lookup for data transfer on established streams. This * should run as fast and furious as possible. We run fast and loose and * rely on the verification tag and port numbers only. We cache and hash * so a stream of back-to-back packets to the same destination (bursty * traffic) will whirl. Because we MD4 hash verification tags when we * generate them, the hash should get good random distribution with minimum * collisions. * */#ifndef SCTP_SLOW_VERIFICATION#define sctp_match_vtag(__sp, __saddr, __daddr, __v_tag, __sport, __dport) \ ( ((__v_tag) == (__sp)->v_tag) && \ ((__sport) == (__sp)->sport) )#else#define sctp_match_vtag(__sp, __saddr, __daddr, __v_tag, __sport, __dport) \ ( ((__v_tag) == (__sp)->v_tag) && \ ((__sport) == (__sp)->sport) && \ ((__dport) == (__sp)->dport) && \ (sctp_find_saddr((__sp),(__daddr))) && \ (sctp_find_daddr((__sp),(__saddr))) )#endifstatic sctp_t *sctp_lookup_vtag(uint32_t v_tag, uint16_t sport, uint16_t dport, uint32_t saddr, uint16_t daddr){ sctp_t *sp; unsigned int hash = sctp_cachefn(v_tag); (void)saddr; (void)daddr; if ( !(sp = sctp_cache[hash]) || !sctp_match_vtag(sp, saddr, daddr, v_tag, sport, dport) ) for ( sp = sctp_vhash[sctp_vhashfn(v_tag)]; sp; sp = sp->next ) if ( sctp_match_vtag(sp, saddr, daddr, v_tag, sport, dport) ) { sctp_cache[hash] = sp; break; } return sp;}/* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP COOKIE ECHO - Special lookup rules for cookie echo chunks * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static sctp_t *sctp_lookup_cookie_echo(ck, v_tag, sport, dport, saddr, daddr) struct sctp_cookie *ck; uint32_t v_tag; uint16_t dport; uint16_t sport; uint32_t daddr; uint32_t saddr;{ sctp_t *sp = NULL; /* quick sanity checks on cookie */ if ( ck->v_tag == v_tag && ck->sport == sport && ck->dport == dport ) { if ( /* RFC 2960 5.2.4 (A) */ ( ck->l_ttag && ck->p_ttag && (sp = sctp_lookup_vtag(ck->l_ttag, sport, dport, saddr, daddr)) ) /* RFC 2960 5.2.4 (B) */ || ( (sp = sctp_lookup_vtag(v_tag, sport, dport, saddr, daddr)) ) /* RFC 2960 5.2.4 (C) */ || ( !ck->l_ttag && !ck->p_ttag && (sp = sctp_lookup_ptag(ck->p_tag, sport, dport, saddr, daddr)) ) /* RFC 2960 5.2.4 (D) */ || ( (sp = sctp_lookup_listen(sport, saddr)) ) ) return(sp); } else rare(); seldom(); return(NULL);}/* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * LOOKUP - Established hash (local verification tag with fallbacks) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * Stream hash lookup with fast path for data. This uses verification tag * when it is available. Source address and port are checked after the * verification tag matches. When called for INIT and COOKIE ECHO messages, * the function returns a listening (bind) hash lookup. For SHUTDOWN * COMPLETE and ABORT messages with the T-bit set, an icmp (peer tag) lookup * is performed instead. */sctp_t *sctp_lookup(struct sctphdr *sh, uint32_t daddr, uint32_t saddr){ sctp_t *sp = NULL; struct sctpchdr *ch = (struct sctpchdr *)(sh+1); int ctype = ch->type & SCTP_CTYPE_MASK; uint32_t v_tag = sh->v_tag; uint16_t dport = sh->dest; uint16_t sport = sh->srce; if ( v_tag ) { /* fast path */ if ( ctype == SCTP_CTYPE_SACK || ctype == SCTP_CTYPE_DATA ) return sctp_lookup_vtag(v_tag, dport, sport, daddr, saddr); switch ( ctype ) { /* See RFC 2960 Section 8.5.1 */ case SCTP_CTYPE_ABORT: case SCTP_CTYPE_SHUTDOWN_COMPLETE: if ( ch->flags & 0x1 ) /* T bit set */ return sctp_lookup_ptag(v_tag, dport, sport, daddr, saddr); default: if ( (sp = sctp_lookup_vtag(v_tag, dport, sport, daddr, saddr)) ) return(sp); if ( ctype == SCTP_CTYPE_ABORT ) /* check abort for conn ind */ if ( (sp = sctp_lookup_listen(dport, daddr)) ) return(sp); case SCTP_CTYPE_INIT: break; case SCTP_CTYPE_COOKIE_ECHO: { struct sctp_cookie *ck = (struct sctp_cookie *)((struct sctp_cookie_echo *)ch)->cookie; return sctp_lookup_cookie_echo(ck, v_tag, dport, sport, daddr, saddr); } } } else if ( ctype == SCTP_CTYPE_INIT ) if ( (sp = sctp_lookup_listen(dport, daddr)) || (sp = sctp_lookup_tcb(dport, sport, daddr, saddr)) ) return(sp); seldom(); return(NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -