📄 sctp_msg.c
字号:
} rare(); return(-ENOBUFS); } rare(); return(-EFAULT);}/* * SEND SHUTDOWN COMPLETE * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static void sctp_send_shutdown_complete(sp) sctp_t *sp;{ mblk_t *mp; sctp_daddr_t *sd; assert(sp); if ( (sd = sctp_route_response(sp)) ) { struct sctp_shutdown_comp *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); if ( (mp = sctp_alloc_msg(sp, clen)) ) { m = (struct sctp_shutdown_comp *)mp->b_wptr; m->ch.type = SCTP_CTYPE_SHUTDOWN_COMPLETE; 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;}/* * SENDING WITHOUT TCB (Responding to OOTB packets) * ------------------------------------------------------------------------- * When sending without an SCTP TCB, we only have the IP header and the SCTP * header from which to work. We have no associated STREAM. These are * usually used for replying to OOTB messages. * * SEND ABORT (Without TCB) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */void sctp_send_abort_ootb(daddr, saddr, sh) uint32_t daddr; uint32_t saddr; struct sctphdr *sh;{ mblk_t *mp; struct sctp_abort *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); assert( sh ); if ( (mp = sctp_alloc_reply(sh, clen)) ) { m = (struct sctp_abort *)mp->b_wptr; m->ch.type = SCTP_CTYPE_ABORT; m->ch.flags = 1; m->ch.len = __constant_htons(clen); mp->b_wptr += plen; sctp_xmit_ootb(daddr, saddr, mp); } else rare();}/* * SEND ABORT (w/ERROR CAUSE) (Without TCB) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static void sctp_send_abort_error_ootb(daddr, saddr, sh, errn, aptr, alen) uint32_t daddr; uint32_t saddr; struct sctphdr *sh; int errn; caddr_t aptr; /* argument ptr */ size_t alen; /* argument len */{ assert( sh ); 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_reply(sh, clen)) ) { m = (struct sctp_abort *)mp->b_wptr; m->ch.type = SCTP_CTYPE_ABORT; m->ch.flags = 1; 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_xmit_ootb(daddr, saddr, mp); } else rare(); return; } sctp_send_abort_ootb(daddr, saddr, sh);}/* * SEND SHUTDOWN COMPLETE (Without TCB) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */void sctp_send_shutdown_complete_ootb(daddr, saddr, sh) uint32_t daddr; uint32_t saddr; struct sctphdr *sh;{ mblk_t *mp; struct sctp_shutdown_comp *m; size_t clen = sizeof(*m); size_t plen = PADC(clen); assert( sh ); if ( (mp = sctp_alloc_reply(sh, clen)) ) { m = (struct sctp_shutdown_comp *)mp->b_wptr; m->ch.type = SCTP_CTYPE_SHUTDOWN_COMPLETE; m->ch.flags = 1; m->ch.len = __constant_htons(clen); mp->b_wptr += plen; sctp_xmit_ootb(daddr, saddr, mp); } else rare();}/* * BIND_REQ: * ------------------------------------------------------------------------- * Bind the stream to the addresses provided in its bound address lists. * There are some errors that may be returned here: * * Any UNIX error. * * NOADDR - A wildcard address was specified and we don't support * wildcards (maybe we will). * * ADDRBUSY - * */int sctp_bind_req(sp, sport, sptr, snum, cons) sctp_t *sp; uint16_t sport; uint32_t *sptr; size_t snum; ulong cons;{ int err; assert( sp ); if ( !cons && !sport ) { rare(); return(-EADDRNOTAVAIL); } if ( (err = sctp_alloc_saddrs(sp, sport, sptr, snum)) ) { rare(); return(err); } if ( cons && (!sp->sanum || !sp->saddr) ) { rare(); return(-EADDRNOTAVAIL); } if ( cons ) sp->s_state = SCTP_LISTEN; else sp->s_state = SCTP_CLOSED; if ( (err = sctp_bind_hash(sp, cons)) ) { rare(); return(err); } sp->conind = cons; return(0);}/* * CONN_REQ: * ------------------------------------------------------------------------- * Connect to the peer. This launches the INIT process. */int sctp_conn_req(sp, dport, dptr, dnum, dp) sctp_t *sp; uint16_t dport; uint32_t *dptr; size_t dnum; mblk_t *dp;{ int err; assert( sp ); if ( !dport ) { rare(); return(-EADDRNOTAVAIL); } if ( (err = sctp_alloc_daddrs(sp, dport, dptr, dnum)) ) { rare(); return(err); } if ( !sp->daddr || !sp->danum ) { rare(); return(-EADDRNOTAVAIL); } sp->v_tag = sctp_get_vtag(sp->daddr->daddr, sp->saddr->saddr, sp->dport, sp->sport); sp->p_tag = 0; if ( (err = sctp_conn_hash(sp)) ) { rare(); return(err); } /* XXX */ if ( (err = sctp_update_routes(sp,1)) ) { rare(); return(err); } sctp_reset(sp); /* clear old information */ sp->n_istr = 0; sp->n_ostr = 0; sp->t_tsn = sp->v_tag; sp->t_ack = sp->v_tag-1; sp->r_ack = 0; /* fake a data request if data in conn req */ if ( dp ) { seldom(); if ( (err = sctp_data_req(sp, sp->ppi, sp->sid, 0, 0, 0, dp)) ) { rare(); return(err); } sctp_send_init(sp); return(0); } if ( (err = sctp_send_init(sp)) ) { rare(); return(err); } return(0);}/* * CONN_RES: * ------------------------------------------------------------------------- */static int sctp_return_more(mblk_t *mp);int sctp_conn_res(sp, cp, ap, dp) sctp_t *sp; mblk_t *cp; sctp_t *ap; mblk_t *dp;{ int err; struct sctp_cookie_echo *m; struct sctp_cookie *ck; uint32_t *daddrs; uint32_t *saddrs; assert( sp ); assert( cp ); assert( ap ); m = (struct sctp_cookie_echo *)cp->b_rptr; ck = (struct sctp_cookie *)m->cookie; daddrs = (uint32_t *)(ck+1); saddrs = daddrs + ck->danum; sctp_unbind(ap); /* we need to rebind the accepting stream */ if ( (err = sctp_alloc_saddrs(ap, ck->sport, saddrs, ck->sanum)) ) { rare(); return(err); } if ( !sctp_saddr_include(ap, ck->saddr, &err) && err ) { rare(); return(err); } if ( (err = sctp_bind_hash(ap, ap->conind)) ) { rare(); return(err); } if ( (err = sctp_alloc_daddrs(ap, ck->dport, daddrs, ck->danum)) ) { rare(); return(err); } if ( !sctp_daddr_include(ap, ck->daddr, &err) && err ) { rare(); return(err); } ap->v_tag = ck->v_tag; ap->p_tag = ck->p_tag; if ( (err = sctp_conn_hash(ap)) ) { rare(); return(err); } /* XXX */ if ( (err = sctp_update_routes(ap,1)) ) { rare(); return(err); } sctp_reset(ap); /* clear old information */ ap->n_istr = ck->n_istr; ap->n_ostr = ck->n_ostr; ap->t_tsn = ck->v_tag; ap->t_ack = ck->v_tag-1; ap->r_ack = ck->p_tsn-1; ap->p_rwnd = ck->p_rwnd; ap->s_state = SCTP_ESTABLISHED; /* process any chunks bundled with cookie echo on accepting stream */ if ( sctp_return_more(cp) > 0 ) sctp_recv_msg(ap, cp); /* fake a data request if data in conn res */ if ( dp ) { if ( (err = sctp_data_req(ap, ap->ppi, ap->sid, 0, 0, 0, dp)) ) { rare(); return(err); } } sctp_send_cookie_ack(ap); /* caller will unlink connect indication */ return(0);}/* * DATA_REQ: * ------------------------------------------------------------------------- */int sctp_data_req(sp, ppi, sid, ord, more, rcpt, mp) sctp_t *sp; uint32_t ppi; uint16_t sid; uint ord; /* when non-zero, indicates ordered delivery */ uint more; /* when non-zero, indicates more data to follow */ uint rcpt; /* when non-zero, indicates receipt conf requested */ mblk_t *mp;{ uint err = 0, flags = 0; sctp_strm_t *st; ensure( mp, return(-EFAULT) ); /* don't allow zero-length data through */ if ( !msgdsize(mp) ) { freemsg(mp); return(0); } if ( !(st = sctp_ostrm_find(sp, sid, &err)) ) { rare(); return(err); } /* we probably want to data ack out of order as well */#if 0 if ( rcpt || (ord && (sp->flags & SCTP_FLAG_DEFAULT_RC_SEL)) )#else if ( rcpt )#endif flags |= SCTPCB_FLAG_CONF; if ( !ord ) { flags |= SCTPCB_FLAG_URG; if ( !st->x.more ) { flags |= SCTPCB_FLAG_FIRST_FRAG; st->x.ppi = ppi; } } else { if ( !st->n.more ) { flags |= SCTPCB_FLAG_FIRST_FRAG; st->n.ppi = ppi; } } if ( !more ) flags |= SCTPCB_FLAG_LAST_FRAG; return sctp_send_data(sp, st, flags, mp);}/* * RESET_REQ: * ------------------------------------------------------------------------- * Don't know what to do here, probably nothing... * * Gee we could keep a copy of the old cookie against the stream of we * actively connected and send a COOKIE ECHO to generate a RESTART at the * other end???? */int sctp_reset_req(sp) sctp_t *sp;{ int err; /* do nothing */ if ( sp->ops->sctp_reset_con && (err = sp->ops->sctp_reset_con(sp)) ) { rare(); return(err); } return(0);}/* * RESET_RES: * ------------------------------------------------------------------------- */int sctp_reset_res(sp) sctp_t *sp;{ mblk_t *cp; if ( !(cp = bufq_dequeue(&sp->conq)) ) { rare(); return(-EFAULT); } return sctp_conn_res(sp, cp, sp, NULL);}/* * DISCON_REQ: * ------------------------------------------------------------------------- */int sctp_discon_req(sp, cp) sctp_t *sp; mblk_t *cp;{ /* * Caller must ensure that sp and cp (if any) are correct and * appropriate. */ if ( cp ) { struct iphdr *iph = (struct iphdr *)cp->b_datap->db_base; struct sctphdr *sh = (struct sctphdr *)(cp->b_datap->db_base + (iph->ihl<<2)); sctp_send_abort_ootb(iph->saddr, iph->daddr, sh); /* conn ind will be unlinked by caller */ return(0); } if ( (1<<sp->s_state)&(SCTPF_NEEDABORT) ) { sctp_send_abort(sp); } else rare(); sctp_disconnect(sp); return(0);}/* * ORDREL_REQ: * ------------------------------------------------------------------------- */int sctp_ordrel_req(sp) sctp_t *sp;{ switch ( sp->s_state ) { case SCTP_ESTABLISHED: if ( !bufq_head(&sp->sndq) && !bufq_head(&sp->rtxq) ) sctp_send_shutdown(sp); else sp->s_state = SCTP_SHUTDOWN_PENDING; return(0); case SCTP_SHUTDOWN_RECEIVED: if ( !bufq_head(&sp->sndq) && !bufq_head(&sp->rtxq) ) sctp_send_shutdown_ack(sp); else sp->s_state = SCTP_SHUTDOWN_RECVWAIT; return(0); } rare();// ptrace(("sp->s_state = %d\n", sp->s_state)); return(-EPROTO);}/* * UNBIND_REQ: * ------------------------------------------------------------------------- */int sctp_unbind_req(sp) sctp_t *sp;{ switch ( sp->s_state ) { case SCTP_SHUTDOWN_ACK_SENT: /* can't wait for SHUTDOWN COMPLETE any longer */ sctp_disconnect(sp); case SCTP_CLOSED: case SCTP_LISTEN: sctp_unbind(sp); return(0); } rare(); return(-EPROTO);}/* * ========================================================================= * * SCTP Peer --> SCTP Primitives (Receive Messages) * * ========================================================================= *//* * RETURN VALUE FUNCTIONS * ------------------------------------------------------------------------- * * RETURN VALUE when expecting more chunks * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */static int sctp_return_more(mp) mblk_t *mp;{ int ret; struct sctpchdr *ch; assert(mp); ch = (struct sctpchdr *)mp->b_rptr; mp->b_rptr += PADC(ntohs(ch->len)); ret = mp->b_wptr - mp->b_rptr; ret = ( ret < 0 || (0 < ret && ret < sizeof(struct sctpchdr)) ) ? -EMSGSIZE : ret; unusual( ret < 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -