📄 sctp_msg.c
字号:
m->ch.flags = 0; m->ch.len = htons(clen); m->i_tag = sp->v_tag; m->a_rwnd = htonl( sp->a_rwnd ); m->n_istr = htons( sp->max_istr ); m->n_ostr = htons( sp->req_ostr ); m->i_tsn = htonl( sp->v_tag ); mp->b_wptr += sizeof(*m); for ( ss = sp->saddr; ss && sanum; ss = ss->next, sanum-- ) { ap = (struct sctp_ipv4_addr *)mp->b_wptr; ap->ph.type = SCTP_PTYPE_IPV4_ADDR; ap->ph.len = htons( sizeof(*ap) ); ap->addr = ss->saddr; mp->b_wptr += PADC( sizeof(*ap) ); } unusual( ss ); unusual( sanum ); if ( sp->ck_inc ) { cp = (struct sctp_cookie_psrv *)mp->b_wptr; cp->ph.type = SCTP_PTYPE_COOKIE_PSRV; cp->ph.len = htons( sizeof(*cp) );; cp->ck_inc = htonl( sp->ck_inc ); mp->b_wptr += PADC( sizeof(*cp) ); } at = (struct sctp_addr_type *)mp->b_wptr; at->ph.type = SCTP_PTYPE_ADDR_TYPE; at->ph.len = htons( sizeof(*at)+sizeof(at->type[0]) ); at->type[0] = SCTP_PTYPE_IPV4_ADDR; mp->b_wptr += PADC( sizeof(*at)+sizeof(at->type[0]) ); sctp_send_msg(sp, sd, mp); mod_timeout(&sp->timer_init, &sctp_init_timeout, sd, sd->rto); unusual( sp->retry ); freechunks(xchg(&sp->retry, mp)); sp->s_state = SCTP_COOKIE_WAIT; return(0); } rare(); return(-ENOBUFS); } rare(); return(-EFAULT);}/* * SEND INIT ACK * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * No s_state change results from replying to an INIT. INIT ACKs are sent * without a TCB but a STREAM is referenced. INIT ACK chunks cannot have any * other chunks bundled with them. (RFC 2960 6.10). */static void sctp_send_init_ack(sp, daddr, sh, ck) sctp_t *sp; uint32_t daddr; struct sctphdr *sh; struct sctp_cookie *ck;{ mblk_t *mp; struct sctp_init_ack *m; struct sctpphdr *ph; struct sctp_cookie *cp; struct sctp_ipv4_addr *ap; struct sctp_init *im = (struct sctp_init *)(sh+1); unsigned char *init = (unsigned char *)im; int anum = ck->danum; int snum = ck->sanum; size_t klen = sizeof(*ph)+raw_cookie_size(ck)+HMAC_SIZE; size_t dlen = sp->sanum * PADC(sizeof(*ap)); size_t clen = sizeof(*m)+dlen+klen; int arem, alen; assert(sp); if ( (mp = sctp_alloc_reply(sh, clen)) ) { sctp_saddr_t *ss; struct sctphdr *rh; rh = ((struct sctphdr *)mp->b_wptr)-1; rh->v_tag = im->i_tag; m = (struct sctp_init_ack *)mp->b_wptr; m->ch.type = SCTP_CTYPE_INIT_ACK; m->ch.flags = 0; m->ch.len = htons(clen); m->i_tag = ck->v_tag; m->a_rwnd = htonl( sp->a_rwnd ); m->n_istr = htons( ck->n_istr ); m->n_ostr = htons( ck->n_ostr ); m->i_tsn = htonl( ck->v_tag ); mp->b_wptr += sizeof(*m); for ( ss = sp->saddr; ss; ss = ss->next ) { ap = (struct sctp_ipv4_addr *)mp->b_wptr; ap->ph.type = SCTP_PTYPE_IPV4_ADDR; ap->ph.len = __constant_htons( sizeof(*ap) ); ap->addr = ss->saddr; mp->b_wptr += PADC(sizeof(*ap)); } ph = (struct sctpphdr *)mp->b_wptr; ph->type = SCTP_PTYPE_STATE_COOKIE; ph->len = htons( klen ); mp->b_wptr += sizeof(*ph); cp = (struct sctp_cookie *)mp->b_wptr; bcopy(ck, cp, sizeof(*cp)); mp->b_wptr += sizeof(*cp); #if 0 /* copy in IP reply options */ if ( ck->opt_len ) { assure(opt); bcopy(opt, mp->b_wptr, optlength(opt)); kfree_s(opt, optlength(opt)); sp->opt = (struct ip_options *)mp->b_wptr; mp->b_wptr += ck->opt_len; }#endif for ( ap = (struct sctp_ipv4_addr *)(init + sizeof(struct sctp_init)), arem = PADC(htons(((struct sctpchdr *)init)->len)) - sizeof(struct sctp_init); anum && arem >= sizeof(struct sctpphdr); arem -= PADC(alen), ap = (struct sctp_ipv4_addr *)(((uint8_t *)ap)+PADC(alen)) ) { if ( (alen = ntohs(ap->ph.len)) > arem ) { assure( alen <= arem ); freemsg(mp); rare(); return; } if ( ap->ph.type == SCTP_PTYPE_IPV4_ADDR ) { /* skip primary */ if ( ap->addr != ck->daddr ) { *((uint32_t *)mp->b_wptr)++ = ap->addr; anum--; } } } for ( ss = sp->saddr; ss; ss = ss->next ) { if ( ss->saddr != ck->saddr ) { *((uint32_t *)mp->b_wptr)++ = ss->saddr; snum--; } } assure( !anum ); assure( !snum ); sctp_sign_cookie(sp, cp); mp->b_wptr += HMAC_SIZE; sctp_xmit_msg(daddr, mp, sp); }}/* * SEND COOKIE ECHO * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * If we fail to launch the COOKIE ECHO and get timers started, we must * return an error to the user interface calling this function. */static int sctp_send_cookie_echo(sp, kptr, klen) sctp_t *sp; caddr_t kptr; size_t klen;{ sctp_daddr_t *sd; assert(sp); if ( (sd = sp->daddr) ) { mblk_t *mp; struct sctp_cookie_echo *m; size_t clen = sizeof(*m)+klen; size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_cookie_echo *)mp->b_wptr; m->ch.type = SCTP_CTYPE_COOKIE_ECHO; m->ch.flags = 0; m->ch.len = htons(clen); bcopy(kptr, (m+1), klen); mp->b_wptr += plen; sctp_bundle_more(sp, sd, mp); sctp_send_msg(sp, sd, mp); mod_timeout(&sp->timer_cookie, &sctp_cookie_timeout, sd, sd->rto); unusual( sp->retry ); freechunks(xchg(&sp->retry, mp)); sp->s_state = SCTP_COOKIE_ECHOED; return(0); } rare(); return(-ENOBUFS); } rare(); return(-EFAULT);}/* * SEND COOKIE ACK * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * SACK and DATA can be bundled with the COOKIE ACK. */static void sctp_send_cookie_ack(sp) sctp_t *sp;{ sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_response(sp)) ) { mblk_t *mp; struct sctp_cookie_ack *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_cookie_ack *)mp->b_wptr; m->ch.type = SCTP_CTYPE_COOKIE_ACK; m->ch.flags = 0; m->ch.len = __constant_htons(clen); mp->b_wptr += plen; sctp_bundle_more(sp, sd, mp); sctp_send_msg(sp, sd, mp); freechunks(mp); } sp->s_state = SCTP_ESTABLISHED; /* start idle timers */ for ( sd = sp->daddr; sd; sd = sd->next ) sctp_reset_idle(sd); }}/* * SEND HEARTBEAT * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * We don't send heartbeats when idle timers expire if we are in the wrong * state, we just reset the idle timer. */static void sctp_send_heartbeat(sp, sd) sctp_t *sp; sctp_daddr_t *sd;{ mblk_t *mp; struct sctp_heartbeat *m; struct sctp_heartbeat_info *h; size_t fill, clen, hlen, plen; assert(sp); assert(sd); fill = sd->hb_fill; clen = sizeof(*m)+sizeof(*h)+fill; hlen = clen - sizeof(struct sctpchdr); plen = PADC(clen); sd->hb_time = jiffies; if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_heartbeat *)mp->b_wptr; m->ch.type = SCTP_CTYPE_HEARTBEAT; m->ch.flags = 0; m->ch.len = htons(clen); h = (struct sctp_heartbeat_info *)(m+1); h->ph.type = SCTP_PTYPE_HEARTBEAT_INFO; h->ph.len = htons(hlen); h->hb_info.timestamp = sd->hb_time; h->hb_info.daddr = sd->daddr; h->hb_info.mtu = sd->mtu; bzero(h->hb_info.fill, fill); mp->b_wptr += plen; sctp_send_msg(sp, sd, mp); freechunks(mp); } mod_timeout(&sd->timer_heartbeat, &sctp_heartbeat_timeout, sd, sd->rto);}/* * SEND HEARTBEAT ACK * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Take the incoming HEARTBEAT message and turn it back around as a HEARTBEAT * ACK message. Note that if the incoming chunk parameters are invalid, so * are the outgoing parameters, this is because the hb_info parameter is * opaque to us. This is consistent with draft-stewart-ong-sctpbakeoff- * sigtran-01. */static void sctp_send_heartbeat_ack(sp, hptr, hlen) sctp_t *sp; caddr_t hptr; size_t hlen;{ sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_response(sp)) ) { mblk_t *mp; struct sctp_heartbeat_ack *m; size_t clen = sizeof(*m)+hlen; size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_heartbeat_ack *)mp->b_wptr; m->ch.type = SCTP_CTYPE_HEARTBEAT_ACK; m->ch.flags = 0; m->ch.len = htons(clen); bcopy(hptr, (m+1), hlen); mp->b_wptr += plen; sctp_send_msg(sp, sd, mp); freechunks(mp); } }}/* * SEND ABORT * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * There is no point in bundling control chunks after an ABORT chunk. Also, * DATA chunks are not to be bundled with ABORT chunks. */static void sctp_send_abort(sp) sctp_t *sp;{ sctp_daddr_t *sd; assert(sp); if ( (1<<sp->s_state) & SCTPF_CONNECTED ) sd = sctp_route_normal(sp); else sd = sp->daddr; if ( sd ) { mblk_t *mp; struct sctp_abort *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_abort *)mp->b_wptr; m->ch.type = SCTP_CTYPE_ABORT; m->ch.flags = 0; m->ch.len = __constant_htons(clen); mp->b_wptr += plen; sctp_send_msg(sp, sd, mp); freechunks(mp); } sp->s_state = sp->conind?SCTP_LISTEN:SCTP_CLOSED; }}/* * SEND ABORT (w/ERROR CAUSE) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Errors (beyond the error header) must be formatted by the called and * indicated by are and len. There is no point in bundling data or control * chunks after and abort chunk. */static void sctp_send_abort_error(sp, errn, aptr, alen) sctp_t *sp; int errn; void *aptr; /* argument ptr */ size_t alen; /* argument len */{ sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_normal(sp)) ) { if ( errn ) { mblk_t *mp; struct sctp_abort *m; struct sctpehdr *eh; size_t elen = sizeof(*eh)+alen; size_t clen = sizeof(*m)+elen; size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_abort *)mp->b_wptr; m->ch.type = SCTP_CTYPE_ABORT; m->ch.flags = 0; m->ch.len = htons(clen); eh = (struct sctpehdr *)(m+1); eh->code = htons(errn); eh->len = htons(elen); bcopy(aptr, (eh+1), alen); mp->b_wptr += plen; sctp_send_msg(sp, sd, mp); freechunks(mp); } sp->s_state = sp->conind?SCTP_LISTEN:SCTP_CLOSED; return; } sctp_send_abort(sp); }}/* * SEND SHUTDOWN * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * RFC 2960 6.2 "... DATA chunks cannot be bundled with SHUTDOWN or SHUTDOWN * ACK chunks ..." * * If we fail to launch the SHUTDOWN and get timers started, we must inform * the user interface calling this function. */static int sctp_send_shutdown(sp) sctp_t *sp;{ mblk_t *mp; sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_normal(sp)) ) { struct sctp_shutdown *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_shutdown *)mp->b_wptr; m->ch.type = SCTP_CTYPE_SHUTDOWN; m->ch.flags = 0; m->ch.len = __constant_htons(clen); m->c_tsn = htonl(sp->r_ack); mp->b_wptr += plen; /* shutdown acks everything but dups and gaps */ sp->sackf &= (SCTP_SACKF_DUP|SCTP_SACKF_GAP); sctp_bundle_more(sp, sd, mp); /* not DATA */ sctp_send_msg(sp, sd, mp); mod_timeout(&sp->timer_shutdown, &sctp_shutdown_timeout, sd, sd->rto);// unusual( sp->retry ); /* not that unusual */ freechunks(xchg(&sp->retry, mp)); sp->s_state = SCTP_SHUTDOWN_SENT; return(0); } rare(); return(-ENOBUFS); } rare(); return(-EFAULT);}/* * SEND SHUTDOWN ACK * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * SHUTDOWN ACK is sent in response to a SHUTDOWN message after all data has * cleared or in reponse to a COOKIE ECHO during the SHUTDOWN_ACK_SENT s_state. * If the error flag is set, we want to bundle and ERROR chunk with the * SHUTDOWN ACK indicating "cookie received while shutting down." * * RFC 2960 6.2. "... DATA chunks cannot be bundled with SHUTDOWN or * SHUTDOWN ACK chunks ..." * * If we fail to launch the SHUTDOWN ACK and get timers started, we must * return an error to the user interface calling this function. */static int sctp_send_shutdown_ack(sp) sctp_t *sp;{ mblk_t *mp; sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_response(sp)) ) { struct sctp_shutdown_ack *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_shutdown_ack *)mp->b_wptr; m->ch.type = SCTP_CTYPE_SHUTDOWN_ACK; m->ch.flags = 0; m->ch.len = __constant_htons(clen); mp->b_wptr += plen; sctp_bundle_more(sp, sd, mp); /* not DATA */ sctp_send_msg(sp, sd, mp); mod_timeout(&sp->timer_shutdown, &sctp_shutdown_timeout, sd, sd->rto); unusual( sp->retry ); freechunks(xchg(&sp->retry, mp)); sp->s_state = SCTP_SHUTDOWN_ACK_SENT; return(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -