📄 sctp_cache.c
字号:
/* * ------------------------------------------------------------------------- * * SCTP Stream handling * * ------------------------------------------------------------------------- * * Allocate an Inbound or Outbound Stream * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */sctp_strm_t *sctp_strm_alloc(stp, sid, errp) sctp_strm_t **stp; uint16_t sid; int *errp;{ sctp_strm_t *st; if ( (st = kmem_cache_alloc(sctp_strm_cachep, SLAB_ATOMIC)) ) { bzero(st, sizeof(*st)); if ( (st->next = (*stp)) ) st->next->prev = &st->next; st->prev = stp; (*stp) = st; st->sid = sid; return(st); } *errp = -ENOMEM; rare(); return(NULL);}/* * Free a Stream * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static void sctp_strm_free(st) sctp_strm_t *st;{ assert(st); if ( (*st->prev = st->next) ) st->next->prev = st->prev; kmem_cache_free(sctp_strm_cachep, st);}/* * Free all Streams * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static void sctp_free_strms(sp) sctp_t *sp;{ sctp_strm_t *st, *st_next; assert(sp); st_next = sp->ostrm; usual( st_next ); while ( (st = st_next) ) { st_next = st->next; sctp_strm_free(st); } sp->ostr = NULL; st_next = sp->istrm; usual( st_next ); while ( (st = st_next) ) { st_next = st->next; sctp_strm_free(st); } sp->istr = NULL;}/* * ========================================================================= * * SCTP Private Data Structure Functions * * ========================================================================= * * We use Linux hardware aligned cache here for speedy access to information * contained in the private data structure. */sctp_t *sctp_alloc_priv(q, spp, cmajor, cminor, ops) queue_t *q; sctp_t **spp; int cmajor; int cminor; struct sctp_ifops *ops;{ sctp_t *sp; assert(q); assert(spp); /* must have these 4 */ ensure( ops->sctp_conn_ind, return(NULL) ); ensure( ops->sctp_conn_con, return(NULL) ); ensure( ops->sctp_data_ind, return(NULL) ); ensure( ops->sctp_discon_ind, return(NULL) ); assure( cmajor ); assure( cminor ); if ( (sp = kmem_cache_alloc(sctp_sctp_cachep, SLAB_ATOMIC)) ) { MOD_INC_USE_COUNT; bzero(sp, sizeof(*sp)); /* link into master list */ if ( (sp->next = *spp) ) sp->next->prev = &sp->next; sp->prev = spp; *spp = sp; RD(q)->q_ptr = WR(q)->q_ptr = sp; sp->rq = RD(q); sp->wq = WR(q); sp->cmajor = cmajor; sp->cminor = cminor; sp->ops = ops; sp->i_state = 0; sp->s_state = SCTP_CLOSED; /* ip defaults */ sp->ip_tos = sctp_default_ip_tos; sp->ip_ttl = sctp_default_ip_ttl; sp->ip_proto = sctp_default_ip_proto; sp->ip_dontroute= sctp_default_ip_dontroute; sp->ip_broadcast= sctp_default_ip_broadcast; sp->ip_priority = sctp_default_ip_priority; /* per association defaults */ sp->max_istr = sctp_default_max_istreams; sp->req_ostr = sctp_default_req_ostreams; sp->max_inits = sctp_default_max_init_retries; sp->max_retrans = sctp_default_assoc_max_retrans; sp->a_rwnd = q->q_hiwat; /* sctp_default_rmem not used */ sp->ck_life = sctp_default_valid_cookie_life; sp->ck_inc = sctp_default_cookie_inc; sp->hmac = sctp_default_mac_type; sp->throttle = sctp_default_throttle_itvl; sp->sid = sctp_default_sid; sp->ppi = sctp_default_ppi; sp->max_sack = sctp_default_max_sack_delay; /* per destination association defaults */ sp->rto_ini = sctp_default_rto_initial; sp->rto_min = sctp_default_rto_min; sp->rto_max = sctp_default_rto_max; sp->rtx_path = sctp_default_path_max_retrans; sp->hb_itvl = sctp_default_heartbeat_itvl; bufq_init(&sp->rcvq); bufq_init(&sp->sndq); bufq_init(&sp->urgq); bufq_init(&sp->errq); bufq_init(&sp->oooq); bufq_init(&sp->dupq); bufq_init(&sp->rtxq); bufq_init(&sp->ackq); bufq_init(&sp->conq); sctp_init_lock(sp); sp->pmtu = 576; sp->s_state = SCTP_CLOSED; } usual(sp); return(sp);}void sctp_free_priv(q) queue_t *q;{ sctp_t *sp; ensure( q, return ); sp = SCTP_PRIV(q); ensure( sp, return ); SCTPHASH_LOCK(); { sp->s_state = SCTP_CLOSED; __sctp_unhash(sp); if ( sp->timer_init ) { rare(); untimeout(xchg(&sp->timer_init, 0)); } if ( sp->timer_cookie ) { rare(); untimeout(xchg(&sp->timer_cookie, 0)); } if ( sp->timer_shutdown ) { rare(); untimeout(xchg(&sp->timer_shutdown,0)); } if ( sp->timer_sack ) { rare(); untimeout(xchg(&sp->timer_sack, 0)); } if ( sp->saddr ) { __sctp_free_saddrs(sp); } if ( sp->daddr ) { __sctp_free_daddrs(sp); } } SCTPHASH_UNLOCK(); unusual(sp->retry); freechunks(xchg(&sp->retry, NULL)); sp->sackf = 0; sp->in_flight = 0; sp->retransmits = 0; sp->n_istr = 0; sp->n_ostr = 0; sp->v_tag = 0; sp->p_tag = 0; sp->p_rwnd = 0; unusual( sp->conq.q_msgs ); bufq_purge(&sp->conq); unusual( sp->rq->q_count ); flushq(sp->rq, FLUSHALL); unusual( sp->wq->q_count ); flushq(sp->wq, FLUSHALL); unusual( sp->rcvq.q_msgs ); bufq_purge(&sp->rcvq); unusual( sp->sndq.q_msgs ); bufq_purge(&sp->sndq); unusual( sp->urgq.q_msgs ); bufq_purge(&sp->urgq); unusual( sp->errq.q_msgs ); bufq_purge(&sp->errq); unusual( sp->dupq.q_msgs ); bufq_purge(&sp->dupq); unusual( sp->dups ); sp->dups = NULL; unusual( sp->ndups ); sp->ndups = 0;#ifdef _DEBUG if ( sp->oooq.q_msgs && sp->oooq.q_head ) { mblk_t *mp; for ( mp = sp->oooq.q_head; mp; mp = mp->b_next ) { sctp_tcb_t *cb = SCTP_TCB(mp); printk("oooq tsn = %u\n", cb->tsn); } }#endif unusual( sp->oooq.q_msgs ); bufq_purge(&sp->oooq); unusual( sp->gaps ); sp->gaps = NULL; unusual( sp->ngaps ); sp->ngaps = 0; unusual( sp->nunds ); sp->nunds = 0;#ifdef _DEBUG if ( sp->rtxq.q_msgs && sp->rtxq.q_head ) { mblk_t *mp; for ( mp = sp->rtxq.q_head; mp; mp = mp->b_next ) { sctp_tcb_t *cb = SCTP_TCB(mp); printk("rtxq tsn = %u\n", cb->tsn); } }#endif unusual( sp->rtxq.q_msgs ); bufq_purge(&sp->rtxq); unusual( sp->nrtxs ); sp->nrtxs = 0; unusual( sp->ackq.q_msgs ); bufq_purge(&sp->ackq); /* do we really need to keep this stuff hanging around for retrieval? */ if ( sp->ostrm || sp->istrm ) { sctp_free_strms(sp); } RD(q)->q_ptr = WR(q)->q_ptr = NULL; if ( (*sp->prev = sp->next) ) sp->next->prev = sp->prev; sp->next = NULL; sp->prev = NULL; kmem_cache_free(sctp_sctp_cachep, sp); MOD_DEC_USE_COUNT;}/* * DISCONNECT * ------------------------------------------------------------------------- * Disconnect the STREAM. The caller must send a disconnect indication to * the user interface if necessary and send an abort if necessary. This just * pulls the stream out of the hashes, stops timers, frees simple * retransmission, and zeros connection info. The stream is left bound and * destination addressses are left allocated. Any connection indications are * left queued against the stream. */void sctp_disconnect(sp) sctp_t *sp;{ assert(sp); SCTPHASH_LOCK(); { sctp_daddr_t *sd; sp->s_state = sp->conind?SCTP_LISTEN:SCTP_CLOSED; /* remove from connected hashes */ __sctp_conn_unhash(sp); /* stop timers */ if ( sp->timer_init ) { untimeout(xchg(&sp->timer_init, 0)); } if ( sp->timer_cookie ) { untimeout(xchg(&sp->timer_cookie, 0)); } if ( sp->timer_shutdown ) { untimeout(xchg(&sp->timer_shutdown, 0)); } if ( sp->timer_sack ) { untimeout(xchg(&sp->timer_sack, 0)); } for ( sd = sp->daddr; sd; sd = sd->next ) { if ( sd->dst_cache ) { dst_release(xchg(&sd->dst_cache,0)); } if ( sd->timer_idle ) { untimeout(xchg(&sd->timer_idle, 0)); } if ( sd->timer_retrans ) { seldom(); untimeout(xchg(&sd->timer_retrans, 0)); } if ( sd->timer_heartbeat ) { seldom(); untimeout(xchg(&sd->timer_heartbeat, 0)); } } } SCTPHASH_UNLOCK(); unusual(sp->retry); freechunks(xchg(&sp->retry, NULL)); sp->sackf = 0; sp->in_flight = 0; sp->retransmits = 0; sp->n_istr = 0; sp->n_ostr = 0; sp->v_tag = 0; sp->p_tag = 0; sp->p_rwnd = 0;}/* * Non-locking version for use from within timeouts (runninga at * bottom-half so don't do bottom-half locks). */void __sctp_disconnect(sp) sctp_t *sp;{ sctp_daddr_t *sd; assert(sp); sp->s_state = sp->conind?SCTP_LISTEN:SCTP_CLOSED; /* remove from connected hashes */ __sctp_conn_unhash(sp); /* stop timers */ if ( sp->timer_init ) { seldom(); untimeout(xchg(&sp->timer_init, 0)); } if ( sp->timer_cookie ) { seldom(); untimeout(xchg(&sp->timer_cookie, 0)); } if ( sp->timer_shutdown ) { seldom(); untimeout(xchg(&sp->timer_shutdown, 0)); } if ( sp->timer_sack ) { seldom(); untimeout(xchg(&sp->timer_sack, 0)); } for ( sd = sp->daddr; sd; sd = sd->next ) { if ( sd->dst_cache ) { seldom(); dst_release(xchg(&sd->dst_cache,0)); } if ( sd->timer_idle ) { seldom(); untimeout(xchg(&sd->timer_idle, 0)); } if ( sd->timer_retrans ) { rare(); untimeout(xchg(&sd->timer_retrans, 0)); } if ( sd->timer_heartbeat ) { rare(); untimeout(xchg(&sd->timer_heartbeat, 0)); } } unusual(sp->retry); freechunks(xchg(&sp->retry, NULL)); sp->sackf = 0; sp->in_flight = 0; sp->retransmits = 0; sp->n_istr = 0; sp->n_ostr = 0; sp->v_tag = 0; sp->p_tag = 0; sp->p_rwnd = 0;}/* * UNBIND * ------------------------------------------------------------------------- * We should already be in a disconnected state. This pulls us from the bind * hashes and deallocates source addresses, any connection indications that * are queued against the stream are purged (these might occur if a * connection indication comes in just before we unbind and we have made an * error somewhere else: normally the response to an X_UNBIND_REQ in a * connection indication state will be a X_ERROR_ACK). */void sctp_unbind(sp) sctp_t *sp;{ assert(sp); SCTPHASH_LOCK(); { sp->s_state = SCTP_CLOSED; __sctp_bind_unhash(sp); __sctp_free_saddrs(sp); } SCTPHASH_UNLOCK(); unusual( sp->conq.q_msgs ); bufq_purge(&sp->conq);}/* * RESET * ------------------------------------------------------------------------- * Clear the connection information hanging around on a stream. This include * any queued data blocks that are waitinga around for retrieval. It is OK * to call this function twice in a row on the same streeam. */void sctp_reset(sp) sctp_t *sp;{ unusual( sp->rq->q_count ); flushq(sp->rq, FLUSHALL); unusual( sp->wq->q_count ); flushq(sp->wq, FLUSHALL); sp->pmtu = 576; /* purge queues */ unusual( sp->rcvq.q_msgs ); bufq_purge(&sp->rcvq); unusual( sp->sndq.q_msgs ); bufq_purge(&sp->sndq); unusual( sp->urgq.q_msgs ); bufq_purge(&sp->urgq); unusual( sp->errq.q_msgs ); bufq_purge(&sp->errq); unusual( sp->dupq.q_msgs ); bufq_purge(&sp->dupq); unusual( sp->dups ); sp->dups = NULL; unusual( sp->ndups ); sp->ndups = 0; unusual( sp->oooq.q_msgs ); bufq_purge(&sp->oooq); unusual( sp->gaps ); sp->gaps = NULL; unusual( sp->ngaps ); sp->ngaps = 0; unusual( sp->nunds ); sp->nunds = 0; unusual( sp->rtxq.q_msgs ); bufq_purge(&sp->rtxq); unusual( sp->nrtxs ); sp->nrtxs = 0; unusual( sp->ackq.q_msgs ); bufq_purge(&sp->ackq); if ( sp->ostrm || sp->istrm ) { sctp_free_strms(sp); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -