📄 sctp_msg.c
字号:
mblk_t *mp = bufq_head(&sp->urgq); size_t swnd = sctp_avail(sp, sd, dmps, *mrem); for ( ; mp && *mrem && swnd; mp = mp->b_next ) { mblk_t *db; sctp_tcb_t *cb = SCTP_TCB(mp); size_t dlen = cb->dlen; size_t plen = PADC(sizeof(struct sctp_data) + dlen); ensure( cb->st, continue );#if defined(_DEBUG)||defined(_SAFE) /* this should only occur if the pmtu is falling */ if ( amps <= *mrem && plen > amps ) { rare(); sctp_frag_chunk(&sp->urgq, mp, amps); dlen = cb->dlen; plen = PADC(sizeof(struct sctp_data) + dlen); }#endif if ( dlen > swnd ) { rare(); return; /* congested */ } if ( plen > *mrem && plen <= dmps ) { rare(); return; /* wait for next packet */ } if ( (mp == cb->st->x.head) ) { rare(); cb->st->x.head = NULL; /* steal partial */ } if ( (db = dupmsg(mp)) ) { uint32_t tsn = sp->t_tsn++; struct sctp_data *m = (struct sctp_data *)db->b_rptr; cb->tsn = tsn; cb->flags |= SCTPCB_FLAG_SENT; cb->trans = 0; cb->sacks = 0; cb->when = jiffies; cb->daddr = sd; m->tsn = htonl( tsn ); sd->in_flight += dlen; sp->in_flight += dlen; *mrem = *mrem > plen ? *mrem - plen : 0; *mlen += plen; **dpp = db; *dpp = &(db->b_next); db->b_next = NULL; bufq_queue(&sp->rtxq, bufq_dequeue(&sp->urgq)); swnd = sctp_avail(sp, sd, dmps, *mrem); continue; } rare(); return; } return;}/* * BUNDLE NEW NORMAL (ORDERED) DATA */static void sctp_bundle_data_normal(sp, sd, dmps, amps, dpp, mrem, mlen) sctp_t *sp; /* association */ sctp_daddr_t *sd; /* destination */ size_t dmps; /* destination maximum payload size */ size_t amps; /* association maximum payload size */ mblk_t ***dpp; /* place to link buffer */ size_t *mrem; /* remaining payload */ size_t *mlen; /* current message length */{ mblk_t *mp = bufq_head(&sp->sndq); size_t swnd = sctp_avail(sp, sd, dmps, *mrem); /* don't bundle normal data without more to send (like a SACK) */ if ( sp->options & SCTP_OPTION_CORK || ( sp->options & SCTP_OPTION_NAGLE && *mlen == sizeof(struct sctphdr) && bufq_size(&sp->sndq) < *mrem>>1 ) ) return; for ( ; mp && *mrem && swnd; mp = mp->b_next ) { mblk_t *db; sctp_tcb_t *cb = SCTP_TCB(mp); size_t dlen = cb->dlen; size_t plen = PADC(sizeof(struct sctp_data) + dlen); ensure( cb->st, continue );#if defined(_DEBUG)||defined(_SAFE) /* this should only occur if the pmtu is falling */ if ( amps <= *mrem && plen > amps ) { rare(); sctp_frag_chunk(&sp->sndq, mp, amps); dlen = cb->dlen; plen = PADC(sizeof(struct sctp_data) + dlen); }#endif if ( dlen > swnd ) { rare(); return; /* congested */ } if ( plen > *mrem && plen <= dmps ) { rare(); return; /* wait for next packet */ } if ( (mp == cb->st->n.head) ) { rare(); cb->st->n.head = NULL; /* steal partial */ } if ( (db = dupmsg(mp)) ) { uint32_t tsn = sp->t_tsn++; cb->tsn = tsn; cb->flags |= SCTPCB_FLAG_SENT;// cb->trans = 1; done by sctp_send_msg */ cb->sacks = 0; cb->when = jiffies; cb->daddr = sd; ((struct sctp_data *)db->b_rptr)->tsn = htonl( tsn ); sd->in_flight += dlen; sp->in_flight += dlen; *mrem = *mrem > plen ? *mrem - plen : 0; *mlen += plen; **dpp = db; *dpp = &(db->b_next); db->b_next = NULL; bufq_queue(&sp->rtxq, bufq_dequeue(&sp->sndq)); swnd = sctp_avail(sp, sd, dmps, *mrem); continue; } rare(); return; } return;}/* * BUNDLE CHUNKS * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Tack on SACK, ERROR, and DATA chunks up to the destination MTU considering * congestion windows and fragmentation sizes. */static void sctp_retrans_timeout(caddr_t data);static void sctp_bundle_more(sp, sd, mp) sctp_t *sp; sctp_daddr_t *sd; mblk_t *mp;{ mblk_t **dpp; size_t mrem, dmps, amps, mlen; size_t htax = sizeof(struct iphdr) + sizeof(struct sctphdr); size_t in_flight; ensure( mp, return ); assert( sp ); assert( sd ); in_flight = sd->in_flight; ensure( sd->mtu > htax, return ); /* FIXME: this is worse... */ ensure( sp->pmtu > htax, return ); /* FIXME: this is worse... */ dmps = sd->mtu - htax; /* destintaion max payload size */ amps = sp->pmtu - htax; /* association max payload size */ mlen = msgdsize(mp); mrem = sd->mtu - sizeof(struct iphdr); mrem = ( mlen < mrem ) ? mrem - mlen : 0; dpp = &(mp->b_next); mp->b_next = NULL; if ( mrem && sp->sackf ) sctp_bundle_sack (sp, sd, dmps, amps, &dpp, &mrem, &mlen); if ( mrem && bufq_head(&sp->errq) ) sctp_bundle_error (sp, sd, dmps, amps, &dpp, &mrem, &mlen); if ( mrem && bufq_head(&sp->urgq) ) sctp_bundle_data_urgent (sp, sd, dmps, amps, &dpp, &mrem, &mlen); if ( mrem && sp->nrtxs ) sctp_bundle_data_retrans(sp, sd, dmps, amps, &dpp, &mrem, &mlen); if ( mrem && bufq_head(&sp->sndq) ) sctp_bundle_data_normal (sp, sd, dmps, amps, &dpp, &mrem, &mlen); SCTP_TCB(mp)->dlen = mlen; if ( sd->in_flight && !sd->timer_retrans ) { set_timeout(&sd->timer_retrans, &sctp_retrans_timeout, sd, sd->rto); } return;}/* * ALLOC MSG * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Allocates a new message block with a hidden transmission control block, an * SCTP message header, and the first chunk of a message. */static mblk_t *sctp_alloc_msg(sp, clen) sctp_t *sp; size_t clen;{ mblk_t *mp; struct sctphdr *sh; sctp_tcb_t *cb; size_t plen = PADC(clen); assert(sp); if ( (mp = allocb(sizeof(*cb)+sizeof(*sh)+plen, BPRI_MED)) ) { mp->b_datap->db_type = M_DATA; cb = (sctp_tcb_t *)mp->b_wptr; bzero(cb, sizeof(*cb)); cb->mp = mp; cb->dlen = sizeof(*sh)+plen; mp->b_rptr += sizeof(*cb); /* hide control block */ mp->b_wptr += sizeof(*cb); sh = (struct sctphdr *)mp->b_wptr; sh->srce = sp->sport; sh->dest = sp->dport; sh->v_tag = sp->p_tag; sh->check = 0; mp->b_wptr += sizeof(*sh); bzero(mp->b_wptr+clen,plen-clen); mp->b_next = NULL; } return(mp);}/* * ALLOC REPLY * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * This is for allocating a message block with a hidden transmission control * block for a message sith an STCP header. This is for out of the blue * replies and all that is required is the SCTP header of the message to * which this is a reply. */static mblk_t *sctp_alloc_reply(rh, clen) struct sctphdr *rh; size_t clen;{ mblk_t *mp; struct sctphdr *sh; sctp_tcb_t *cb; size_t plen = PADC(clen); assert(rh); if ( (mp = allocb(sizeof(*cb)+sizeof(*sh)+plen, BPRI_MED)) ) { mp->b_datap->db_type = M_DATA; cb = (sctp_tcb_t *)mp->b_wptr; bzero(cb, sizeof(*cb)); cb->mp = mp; cb->dlen = sizeof(*sh)+plen; mp->b_rptr += sizeof(*cb); /* hide control block */ mp->b_wptr += sizeof(*cb); sh = (struct sctphdr *)mp->b_wptr; sh->srce = rh->dest; sh->dest = rh->srce; sh->v_tag = rh->v_tag; sh->check = 0; mp->b_wptr += sizeof(*sh); bzero(mp->b_wptr+clen,plen-clen); mp->b_next = NULL; } return(mp);}/* * ROUTE SELECTION * ------------------------------------------------------------------------- * * ROUTE NORMAL * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Send to the normal transmit (primary) address. If that has timedout, we * use the retransmit (secondary) address. We always use the secondary * address if we have retransmit chunks to bundle or if we have be receiving * duplicates (our SACKs are not getting through on the primary address). * */static sctp_daddr_t *sctp_route_normal(sp) sctp_t *sp;{ sctp_daddr_t *sd; assert(sp); if ( sctp_update_routes(sp,1) ) { rare(); /* we have no viable route */ if ( (1<<sp->s_state) & (SCTPF_HAVEUSER) ) { sp->ops->sctp_discon_ind(sp, SCTP_ORIG_PROVIDER, -EHOSTUNREACH, NULL); } else rare(); __sctp_disconnect(sp); return(NULL); } sd = sp->taddr; normal(sd);#if 0 if ( ( !sd || ((sd->retransmits || sp->nrtxs) && sd->max_retrans) ) && sp->raddr ) sd = sp->raddr;// if ( !sd || ((sd->retransmits || sp->nrtxs) && sd->max_retrans) || (sp->sackf & SCTP_SACKF_DUP) ) if ( !sd || (sp->nrtxs && sd->max_retrans) || (sp->sackf & SCTP_SACKF_DUP) ) sd = sp->raddr; /* might be same address */#endif return(sd);}/* * ROUTE RESPONSE * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * In response to control chunks we normally send back to the address that * the control chunk came from. If that address is unusable or wasn't * provided we send as normal. */static sctp_daddr_t *sctp_route_response(sp) sctp_t *sp;{ sctp_daddr_t *sd; assert(sp); sd = sp->caddr; if ( !sd || !sd->dst_cache || sd->retransmits ) sd = sctp_route_normal(sp); normal(sd); return(sd);}/* * WAKEUP (Send SACK, ERROR, DATA) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */void sctp_transmit_wakeup(sp) sctp_t *sp;{ int i; mblk_t *mp; sctp_daddr_t *sd; int loop_max = 3000; assert(sp); sctp_lock(sp); if ( (1<<sp->s_state) & SCTPF_SENDING ) { for ( i=0; i<loop_max; i++ ) { /* placed in order of probability */ if ( bufq_head(&sp->sndq) || (sp->sackf & SCTP_SACKF_NOW) || sp->nrtxs || bufq_head(&sp->urgq) || bufq_head(&sp->errq) ) { if ( !(sd = sctp_route_normal(sp)) ) { rare(); break; } if ( !(mp = sctp_alloc_msg(sp, 0)) ) { rare(); break; } sctp_bundle_more(sp, sd, mp); if ( mp->b_next ) { sctp_send_msg(sp, sd, mp); freechunks(mp); continue; } unusual( bufq_head(&sp->sndq) ); unusual( bufq_head(&sp->urgq) ); unusual( bufq_head(&sp->errq) ); unusual( sp->sackf & SCTP_SACKF_NOD ); unusual( sp->nrtxs ); if ( sp->nrtxs ) ptrace(("sp->nrtxs = %u\n",sp->nrtxs)); rare(); freechunks(mp);#if _DEBUG for ( mp = bufq_head(&sp->sndq); mp; mp = mp->b_next ) { sctp_tcb_t *cb = SCTP_TCB(mp); printk("sndq: mp = %08x, dlen = %u\n", (uint)mp, cb->dlen); } for ( mp = bufq_head(&sp->urgq); mp; mp = mp->b_next ) { sctp_tcb_t *cb = SCTP_TCB(mp); printk("urgq: mp = %08x, dlen = %u\n", (uint)mp, cb->dlen); } for ( mp = bufq_head(&sp->rtxq); mp; mp = mp->b_next ) { sctp_tcb_t *cb = SCTP_TCB(mp); printk("rtxq: mp = %08x, dlen = %u, tsn = %u\n", (uint)mp, cb->dlen, cb->tsn); }#endif } break; } assure( i < loop_max ); } sctp_unlock(sp); return;}/* * ========================================================================= * * SCTP State Machine TIMEOUTS * * ========================================================================= */static void sctp_send_heartbeat(sctp_t *sp, sctp_daddr_t *sd);static void sctp_reset_idle(sctp_daddr_t *sd);/* * ASSOCIATION TIMEOUT FUNCTION * ------------------------------------------------------------------------- */static int sctp_assoc_timedout(sp, sd, rmax) sctp_t *sp; sctp_daddr_t *sd; size_t rmax;{ assert( sp ); assert( sd ); /* RFC 2960 6.3.3 E1 and 7.2.3, E2, E3 and 8.3 */ sd->ssthresh = sd->cwnd>>1 > sd->mtu<<1 ? sd->cwnd>>1 : sd->mtu<<1; sd->cwnd = sd->mtu; sd->rto = sd->rto ? sd->rto<<1 : 1; sd->rto = sd->rto_min > sd->rto ? sd->rto_min : sd->rto; sd->rto = sd->rto_max < sd->rto ? sd->rto_max : sd->rto; /*See RFC 2960 Section 8.3 */ if ( sd->retransmits++ >= sd->max_retrans ) { if ( sd->dst_cache ) dst_negative_advice(&sd->dst_cache); if ( sd->retransmits == sd->max_retrans+1 ) { /* * IMPLEMENTATION NOTE:- When max_retrans and * rto_max are set to zero, we are cruel on * destinations that drop a single packet due to * noise. This forces an immediate heartbeat on the * destination so that it can be made available again * quickly it if passes the heartbeat. */ if ( (1<<sp->s_state) & (SCTPF_CONNECTED|SCTPF_CLOSING) ) { if ( sd->timer_idle ) untimeout(xchg(&sd->timer_idle,0)); sctp_send_heartbeat(sp, sd); } } else { if ( (1<<sp->s_state) & (SCTPF_CONNECTED) ) return(0); } } /*See RFC 2960 Section 8.2 */ if ( rmax && sp->retransmits++ >= rmax ) { seldom(); if ( (1<<sp->s_state) & (SCTPF_HAVEUSER) ) { sp->ops->sctp_discon_ind(sp, SCTP_ORIG_PROVIDER, -ETIMEDOUT, NULL); } else rare(); __sctp_disconnect(sp); return(-ETIMEDOUT); } return(0);}/* * INIT TIMEOUT (T1-init) * ------------------------------------------------------------------------- * The init timer has expired indicating that we have not received an INIT * ACK within timer T1-init. This means that we should attempt to retransmit * the INIT until we have attempted Max.Init.Retrans times. */static void sctp_init_timeout(data) caddr_t data;{ sctp_t *sp; sctp_daddr_t *sd; sd = (sctp_daddr_t *)data; assert( sd ); sp = sd->sp; assert( sp ); if ( sctp_locked(sp) ) { seldom(); sp->timer_init = timeout(sctp_init_timeout, (caddr_t)sd, 1); return; } sp->timer_init = 0; if ( sp->s_state != SCTP_COOKIE_WAIT ) { rare(); return; } if ( sctp_assoc_timedout(sp, sd, sp->max_inits) ) { seldom(); return; } sd = sp->taddr; /* might have new primary */ ensure( sd, return ); set_timeout(&sp->timer_init, sctp_init_timeout, (caddr_t)sd, sd->rto); usual( sp->retry ); sctp_send_msg(sp, sd, sp->retry);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -