📄 sctp_n.c
字号:
break; mp->b_cont = NULL; /* absorbed mp->b_cont */ return(0); } } seldom(); err = NACCESS; break; /* no permission for requested address */ } seldom(); err = NBADADDR; break; /* addresss is unusable */ } seldom(); err = NBADOPT; break; /* options are unusable */ } seldom(); err = NBADQOSTYPE; break; /* QOS structure type not supported */ } seldom(); err = NBADOPT; break; /* options are unusable */ } seldom(); err = -EINVAL; break; /* invalid message format */ } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } while(0); seldom(); return n_error_ack(sp, N_CONN_REQ, err);}/* * N_CONN_RES 1 - Accept previous connection indication * ------------------------------------------------------------------------- * IMPLEMENTATION NOTES:- Sequence numbers are actually the address of the * mblk which contains the COOKIE-ECHO chunk and contains the cookie as a * connection indication. To find if a particular sequence number is valid, * we walk the connection indication queue looking for a mblk with the same * address as the sequence number. Sequence numbers are only valid on the * stream for which the connection indication is queued. */static mblk_t *n_seq_check(sctp_t *sp, ulong seq){ mblk_t *mp = bufq_head(&sp->conq); for ( ; mp && mp != (mblk_t *)seq; mp = mp->b_next ); usual(mp); return(mp);}sctp_t *sctp_n_list;static sctp_t *n_tok_check(sctp_t *sp, ulong tok){ sctp_t *ap; queue_t *aq = (queue_t *)tok; for ( ap = sctp_n_list; ap && ap->rq != aq; ap = ap->next ); usual(ap); return(ap);}static int n_conn_res(sctp_t *sp, mblk_t *mp){ int err; mblk_t *cp; sctp_t *ap; size_t mlen = mp->b_wptr - mp->b_rptr; N_conn_res_t *p = (N_conn_res_t *)mp->b_rptr; N_qos_sel_conn_sctp_t *q = (N_qos_sel_conn_sctp_t *)(mp->b_rptr + p->QOS_offset); do { if ( sp->i_state == NS_WRES_CIND ) { sp->i_state = NS_WACK_CRES; if ( mlen >= sizeof(*p) ) { if ( !p->QOS_length || mlen >= p->QOS_offset + p->QOS_length ) { if ( !p->QOS_length || q->n_qos_type == N_QOS_SEL_CONN_SCTP ) { if ( !p->QOS_length || p->QOS_length == sizeof(*q) ) { if ( (cp = n_seq_check(sp, p->SEQ_number)) ) { if ( (ap = n_tok_check(sp, p->TOKEN_value)) && ( ap==sp || ((1<<ap->i_state)&(NSF_UNBND|NSF_IDLE))) ) { if ( ap->i_state != NS_IDLE || !ap->conind ) { /* protect at least r00t streams from users */ if ( sp->cred.cr_uid == 0 || ap->cred.cr_uid != 0 ) { uint ap_oldstate = ap->i_state; uint ap_oldflags = ap->flags; ap->i_state = NS_DATA_XFER; ap->flags &= ~(SCTP_FLAG_REC_CONF_OPT|SCTP_FLAG_EX_DATA_OPT); if ( p->CONN_flags & REC_CONF_OPT ) ap->flags |= SCTP_FLAG_REC_CONF_OPT; if ( p->CONN_flags & EX_DATA_OPT ) ap->flags |= SCTP_FLAG_EX_DATA_OPT; if ( (err = sctp_conn_res(sp, cp, ap, mp->b_cont)) ) { ap->i_state = ap_oldstate; ap->flags = ap_oldflags; break; } mp->b_cont = NULL; /* absorbed mp->b_cont */ return n_ok_ack(sp, N_CONN_RES, p->SEQ_number, p->TOKEN_value); } seldom(); err = NACCESS; break; /* no access to accepting queue */ } seldom(); err = NBADTOKEN; break; /* accepting queue is listening */ } seldom(); err = NBADTOKEN; break; /* accepting queue id is invalid */ } seldom(); err = NBADSEQ; break; /* connection ind reference is invalid */ } seldom(); err = NBADOPT; break; /* quality of service options are bad */ } seldom(); err = NBADQOSTYPE; break; /* quality of service options are bad */ } seldom(); err = NBADOPT; break; /* quality of service options are bad */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } while(0); seldom(); return n_error_ack(sp, N_CONN_REQ, err);}/* * N_DISCON_REQ 2 - NC disconnection request * ------------------------------------------------------------------------- */static int n_discon_req(sctp_t *sp, mblk_t *mp){ int err; mblk_t *cp = NULL; size_t mlen = mp->b_wptr - mp->b_rptr; N_discon_req_t *p = (N_discon_req_t *)mp->b_rptr; do { if ( (1<<sp->i_state) & ( NSF_WCON_CREQ | NSF_WRES_CIND | NSF_DATA_XFER | NSF_WCON_RREQ | NSF_WRES_RIND ) ) { switch ( sp->i_state ) { case NS_WCON_CREQ: sp->i_state = NS_WACK_DREQ6; break; case NS_WRES_CIND: sp->i_state = NS_WACK_DREQ7; break; case NS_DATA_XFER: sp->i_state = NS_WACK_DREQ9; break; case NS_WCON_RREQ: sp->i_state = NS_WACK_DREQ10; break; case NS_WRES_RIND: sp->i_state = NS_WACK_DREQ11; break; } if ( mlen >= sizeof(*p) ) { if ( !p->RES_length ) { if ( sp->i_state != NS_WACK_DREQ7 || (cp = n_seq_check(sp, p->SEQ_number)) ) { /* * XXX: What do we do with the disconnect reason? Nothing? */ if ( (err = sctp_discon_req(sp, cp)) ) break; return n_ok_ack(sp, N_DISCON_REQ, p->SEQ_number, 0); } seldom(); err = NBADSEQ; break; /* connection ind reference is invalid */ } seldom(); err = NBADADDR; break; /* responding address is inavlid */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } while(0); seldom(); return n_error_ack(sp, N_DISCON_REQ, err);}/* * N_DATA_REQ 3 - Connection-Mode data transfer request * ------------------------------------------------------------------------- */static int m_error_reply(sctp_t *sp, int err){ mblk_t *mp; switch ( err ) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: seldom(); return(err); case 0: case 1: case 2: never(); return(err); } if ( (mp = allocb(2, BPRI_HI)) ) { mp->b_datap->db_type = M_ERROR; *(mp->b_wptr)++ = err<0?-err:err; *(mp->b_wptr)++ = err<0?-err:err; putnext(sp->rq, mp); return(0); } seldom(); return(-ENOBUFS);}static int n_write(sctp_t *sp, mblk_t *mp){ int err; do { if ( sp->i_state != NS_IDLE ) { if ( (1<<sp->i_state) & (NSF_DATA_XFER|NSF_WRES_RIND) ) { ulong ppi = sp->ppi; ulong sid = sp->sid; ulong ord = 1; ulong more = 0; ulong rcpt = 0; if ( (err = sctp_data_req(sp, ppi, sid, ord, more, rcpt, mp)) ) break; return(1); /* absorbed mp */ } seldom(); err = -EPROTO; break; /* would place interface out of state */ } seldom(); return(0); break; /* ignore in idle state */ } while(0); seldom(); return m_error_reply(sp, err);}static int n_data_req(sctp_t *sp, mblk_t *mp){ int err; N_qos_sel_data_sctp_t *q = NULL; size_t mlen = mp->b_wptr - mp->b_rptr; N_data_req_t *p = (N_data_req_t *)mp->b_rptr; do { if ( sp->i_state != NS_IDLE ) { if ( mlen >= sizeof(*p) ) { if ( mlen >= sizeof(*p)+sizeof(*q) ) q = (N_qos_sel_data_sctp_t *)(p+1); if ( q->n_qos_type != N_QOS_SEL_DATA_SCTP ) q = NULL; if ( (1<<sp->i_state) & (NSF_DATA_XFER|NSF_WRES_RIND) ) { ulong ppi = q?q->ppi:sp->ppi; ulong sid = q?q->sid:sp->sid; ulong ord = 1; ulong more = p->DATA_xfer_flags & N_MORE_DATA_FLAG; ulong rcpt = p->DATA_xfer_flags & N_RC_FLAG; if ( (err = sctp_data_req(sp, ppi, sid, ord, more, rcpt, mp->b_cont)) ) break; mp->b_cont = NULL; /* absorbed mp->b_cont */ return(0); } seldom(); err = -EPROTO; break; /* would place interface out of state */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } seldom(); return(0); /* ignore in idle state */ } while(0); seldom(); return m_error_reply(sp, err);}/* * N_EXDATA_REQ 4 - Expedited data request * ------------------------------------------------------------------------- */static int n_exdata_req(sctp_t *sp, mblk_t *mp){ int err; N_qos_sel_data_sctp_t *q = NULL; size_t mlen = mp->b_wptr - mp->b_rptr; N_exdata_req_t *p = (N_exdata_req_t *)mp->b_rptr; do { if ( sp->i_state != NS_IDLE ) { if ( mlen >= sizeof(*p) ) { if ( mlen >= sizeof(*p)+sizeof(*q) ) q = (N_qos_sel_data_sctp_t *)(p+1); if ( q->n_qos_type != N_QOS_SEL_DATA_SCTP ) q = NULL; if ( (1<<sp->i_state) & (NSF_DATA_XFER|NSF_WRES_RIND) ) { ulong ppi = q?q->ppi:sp->ppi; ulong sid = q?q->sid:sp->sid; ulong ord = 0; ulong more = 0; ulong rcpt = 0; if ( (err = sctp_data_req(sp, ppi, sid, ord, more, rcpt, mp->b_cont)) ) break; mp->b_cont = NULL; /* absorbed mp->b_cont */ return(0); } seldom(); err = -EPROTO; break; /* would place interface out of state */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } seldom(); return(0); /* ignore in idle state */ } while(0); seldom(); return m_error_reply(sp, err);}/* * N_INFO_REQ 5 - Information request * ------------------------------------------------------------------------- */static int n_info_req(sctp_t *sp, mblk_t *mp){ (void)mp; return n_info_ack(sp);}/* * N_BIND_REQ 6 - Bind a NS user to network address * ------------------------------------------------------------------------- */static int n_bind_req(sctp_t *sp, mblk_t *mp){ int err; size_t mlen = mp->b_wptr - mp->b_rptr; N_bind_req_t *p = (N_bind_req_t *)mp->b_rptr; do { if ( sp->i_state == NS_UNBND ) { sp->i_state = NS_WACK_BREQ; if ( mlen >= sizeof(*p) ) { struct sctp_addr *a = (struct sctp_addr *)(mp->b_rptr + p->ADDR_offset); size_t anum = (p->ADDR_length - sizeof(a->port))/sizeof(a->addr[0]); if ( ( mlen >= p->ADDR_offset + p->ADDR_length ) && ( p->ADDR_length == sizeof(a->port)+anum*sizeof(a->addr[0]) ) ) { /* we don't allow wildcards just yet */ if ( anum && ( a->port || (a->port = sctp_get_port()) ) ) { if ( sp->cred.cr_uid == 0 || a->port >= 1024 ) { if ( (err = sctp_bind_req(sp, a->port, a->addr, anum, p->CONIND_number)) ) break; return n_bind_ack(sp); } seldom(); err = NACCESS; break; /* no permission for requested address */ } seldom(); err = NNOADDR; break; /* could not allocate address */ } seldom(); err = NBADADDR; break; /* address is invalid */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } while(0); seldom(); return n_error_ack(sp, N_BIND_REQ, err);}/* * N_UNBIND_REQ 7 - Unbind NS user from network address * ------------------------------------------------------------------------- */static int n_unbind_req(sctp_t *sp, mblk_t *mp){ int err; N_unbind_req_t *p = (N_unbind_req_t *)mp->b_rptr; (void)p; do { if ( sp->i_state == NS_IDLE ) { sp->i_state = NS_WACK_UREQ; if ( (err = sctp_unbind_req(sp)) ) break; return n_ok_ack(sp, N_UNBIND_REQ, 0, 0); } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } while(0); seldom(); return n_error_ack(sp, N_UNBIND_REQ, err);}/* * N_OPTMGMT_REQ 9 - Options management request * ------------------------------------------------------------------------- */static int n_optmgmt_req(sctp_t *sp, mblk_t *mp){ int err; size_t mlen = mp->b_wptr - mp->b_rptr; N_optmgmt_req_t *p = (N_optmgmt_req_t *)mp->b_rptr; N_qos_sel_info_sctp_t *q = (N_qos_sel_info_sctp_t *)(mp->b_rptr + p->QOS_offset); do { if ( sp->i_state == NS_IDLE ) sp->i_state = NS_WACK_OPTREQ; if ( mlen >= sizeof(*p) ) { if ( !p->QOS_length || mlen >= p->QOS_offset + p->QOS_length ) { if ( !p->QOS_length || q->n_qos_type == N_QOS_SEL_INFO_SCTP ) { if ( !p->QOS_length || p->QOS_length == sizeof(*q) ) { if ( p->QOS_length ) { if ( q->i_streams != -1UL ) sp->max_istr = q->i_streams?q->i_streams:1; if ( q->o_streams != -1UL ) sp->req_ostr = q->o_streams?q->o_streams:1; if ( q->ppi != -1UL ) sp->ppi = q->ppi; if ( q->sid != -1UL ) sp->sid = q->sid; if ( q->max_inits != -1UL ) sp->max_inits = q->max_inits; if ( q->max_retrans != -1UL ) sp->max_retrans = q->max_retrans; if ( q->ck_life != -1UL ) sp->ck_life = q->ck_life; if ( q->ck_inc != -1UL ) sp->ck_inc = q->ck_inc; if ( q->hmac != -1UL ) sp->hmac = q->hmac; if ( q->throttle != -1UL ) sp->throttle = q->throttle; if ( q->max_sack != -1UL ) sp->max_sack = q->max_sack; if ( q->rto_ini != -1UL ) sp->rto_ini = q->rto_ini; if ( q->rto_min != -1UL ) sp->rto_min = q->rto_min; if ( q->rto_max != -1UL ) sp->rto_max = q->rto_max; if ( q->rtx_path != -1UL ) sp->rtx_path = q->rtx_path; if ( q->hb_itvl != -1UL ) sp->hb_itvl = q->hb_itvl; if ( q->options != -1UL ) sp->options = q->options; } if ( p->OPTMGMT_flags & DEFAULT_RC_SEL ) sp->flags |= SCTP_FLAG_DEFAULT_RC_SEL; else sp->flags &= ~SCTP_FLAG_DEFAULT_RC_SEL; return n_ok_ack(sp, N_OPTMGMT_REQ, 0, 0); } seldom(); err = NBADOPT; break; /* QOS options were invalid */ } seldom(); err = NBADQOSTYPE; break; /* QOS structure type not supported */ } seldom(); err = NBADOPT; break; /* QOS options were invalid */ } seldom(); err = -EINVAL; break; /* invalid primitive format */ } while(0); seldom(); return n_error_ack(sp, N_OPTMGMT_REQ, err);}/* * N_RESET_REQ 25 - NC reset request * ------------------------------------------------------------------------- */static int n_reset_req(sctp_t *sp, mblk_t *mp){ int err; size_t mlen = mp->b_wptr - mp->b_rptr; N_reset_req_t *p = (N_reset_req_t *)mp->b_wptr; do { if ( sp->i_state != NS_IDLE ) { if ( sp->i_state == NS_DATA_XFER ) { sp->i_state = NS_WCON_RREQ; (void)p; (void)mlen; if ( (err = sctp_reset_req(sp)) ) break; return(0); } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } seldom(); return(0); /* ignore in idle state */ } while(0); seldom(); return n_error_ack(sp, N_RESET_REQ, err);}/* * N_RESET_RES 27 - Reset processing accepted * ------------------------------------------------------------------------- */static int n_reset_res(sctp_t *sp, mblk_t *mp){ int err; size_t mlen = mp->b_wptr - mp->b_rptr; N_reset_res_t *p = (N_reset_res_t *)mp->b_wptr; do { if ( sp->i_state != NS_IDLE ) { if ( sp->i_state == NS_WRES_RIND ) { sp->i_state = NS_WACK_RRES; (void)p; (void)mlen; if ( (err = sctp_reset_res(sp)) ) break; return n_ok_ack(sp, N_RESET_RES, 0, 0); } seldom(); err = NOUTSTATE; break; /* would place interface out of state */ } seldom(); return(0); /* ignore in idle state */ } while(0); seldom(); return n_error_ack(sp, N_RESET_RES, err);}/* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= * * M_PROTO, M_PCPROTO Handling * * ------------------------------------------------------------------------- */static intsctp_w_proto(queue_t *q, mblk_t *mp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -