?? mtp_tpi.c
字號:
static inline fastcall __unlikely intmtp_optmgmt_req(struct mtp *mtp, queue_t *q, mblk_t *msg, struct mtp_opts *opt, mtp_ulong flags){ struct MTP_optmgmt_req *p; mblk_t *mp; size_t opt_len = t_opts_size(opt); size_t msg_len = sizeof(*p) + opt_len; if (likely((mp = mi_allocb(q, msg_len, BPRI_MED)) != NULL)) { if (likely(canputnext(mtp->wq))) { DB_TYPE(mp) = M_PROTO; p = (typeof(p)) mp->b_wptr; p->mtp_primitive = MTP_OPTMGMT_REQ; p->mtp_opt_length = opt_len; p->mtp_opt_offset = sizeof(*p); p->mtp_mgmt_flags = flags; mp->b_wptr += sizeof(*p); t_build_opts(opt, mp->b_wptr); mp->b_wptr += opt_len; freemsg(msg); mi_strlog(q, STRLOGTX, SL_TRACE, "MTP_OPTMGMT_REQ ->"); putnext(mtp->wq, mp); return (0); } freeb(mp); return (-EBUSY); } return (-ENOBUFS);}/** * mtp_transfer_req: - issue an MTP_TRANSFER_REQ primitive * @mtp: MTP private data * @q: active queue * @bp: message block to free upon success * @dst: destination address (or NULL) * @pri: message priority * @sls: signalling link selection * @dp: user data */static inline fastcall __unlikely intmtp_transfer_req(struct mtp *mtp, queue_t *q, mblk_t *bp, struct mtp_addr *dst, mtp_ulong pri, mtp_ulong sls, mblk_t *dp){ struct MTP_transfer_req *p; mblk_t *mp; size_t dst_len = dst ? sizeof(*dst) : 0; size_t msg_len = sizeof(*p) + dst_len; if (likely((mp = mi_allocb(q, msg_len, BPRI_MED)) != NULL)) { if (likely(bcanputnext(mtp->wq, dp->b_band))) { DB_TYPE(mp) = M_PROTO; mp->b_band = dp->b_band; p = (typeof(p)) mp->b_wptr; p->mtp_primitive = MTP_TRANSFER_REQ; p->mtp_dest_length = dst_len; p->mtp_dest_offset = dst_len ? sizeof(*p) : 0; p->mtp_mp = pri; p->mtp_sls = sls; mp->b_wptr += sizeof(*p); bcopy(dst, mp->b_wptr, dst_len); mp->b_wptr += dst_len; mp->b_cont = dp; if (bp) freeb(bp); mi_strlog(q, STRLOGDA, SL_TRACE, "MTP_TRANSFER_REQ ->"); putnext(mtp->wq, mp); return (0); } freeb(mp); return (-EBUSY); } return (-ENOBUFS);}/* * ------------------------------------------------------------------------- * * Primitives received from above. * * ------------------------------------------------------------------------- *//** * t_data: - process M_DATA message * @mtp: private structure * @q: active queue * @mp: the message * * To support pseudo-connectionless modes, when this message is sent for T_CLTS we should send the * data to the same adress and with the same options as the last T_UNITDATA_REQ primitive. */static inline fastcall __hot_read intt_data(struct mtp *mtp, queue_t *q, mblk_t *mp){ const size_t dlen = msgdsize(mp); if (mtp->prot.SERV_type == T_CLTS) goto notsupport; if (mtp_get_state(mtp) == TS_IDLE) goto discard; if (mtp_not_state(mtp, (TSF_DATA_XFER | TSF_WREQ_ORDREL))) goto outstate; if (dlen == 0 || dlen > mtp->prot.TSDU_size || dlen > mtp->prot.TIDU_size) goto baddata; return mtp_transfer_req(mtp, q, NULL, &mtp->dst, mtp->options.mp, mtp->options.sls, mp); baddata: mi_strlog(q, 0, SL_TRACE, "bad data size %lu", (ulong)dlen); goto error; outstate: mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; discard: mi_strlog(q, 0, SL_TRACE, "ignore in idle state"); freemsg(mp); return (0); notsupport: mi_strlog(q, 0, SL_TRACE, "primitive not supported for T_CLTS"); goto error; error: return m_error(mtp, q, mp, EPROTO);}/** * t_conn_req: - process T_CONN_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message * * As MTP is really a connectionless protocol, when we form a connection we simply remember the * destination address. Some interim MTPs had the abilitty to send a UPT (User Part Test) message. * If the protocol variant has this ability, we wait for the result of the User Part Test before * confirming the connection. */static inline fastcall __unlikely intt_conn_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ int err = -EFAULT; const struct T_conn_req *p = (typeof(p)) mp->b_rptr; struct mtp_addr *dst; struct mtp_opts opts = { 0L, NULL, }; if (mtp_get_state(mtp) != TS_IDLE) goto outstate; if (mtp->prot.SERV_type == T_CLTS) goto notsupport; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->DEST_offset + p->DEST_length) goto badprim; if (mp->b_wptr < mp->b_rptr + p->OPT_offset + p->OPT_length) goto badprim; dst = (typeof(dst)) (mp->b_rptr + p->DEST_offset); if (!p->DEST_length) goto noaddr; if (p->DEST_length < sizeof(*dst)) goto badaddr; if (dst->family != AF_MTP) goto badaddr; if (dst->si == 0 && mtp->src.si == 0) goto noaddr; if (dst->si < 3 && mtp->src.si != 0) goto badaddr; if (dst->si < 3 && mtp->cred.cr_uid != 0) goto acces; if (dst->si != mtp->src.si && mtp->src.si != 0) goto badaddr; if (t_parse_opts(&opts, mp->b_rptr + p->OPT_offset, p->OPT_length)) goto badopt; /* TODO: set options first */ if (mp->b_cont) { putbq(q, mp->b_cont); /* hold back data */ mp->b_cont = NULL; /* abosrbed mp->b_cont */ } mtp->dst = *dst; mtp_set_state(mtp, TS_WACK_CREQ); return mtp_conn_req(mtp, q, mp, dst, 0, NULL); badopt: err = TBADOPT; mi_strlog(q, 0, SL_TRACE, "bad options"); goto error; acces: err = TACCES; mi_strlog(q, 0, SL_TRACE, "no permission for address"); goto error; badaddr: err = TBADADDR; mi_strlog(q, 0, SL_TRACE, "address is unusable"); goto error; noaddr: err = TNOADDR; mi_strlog(q, 0, SL_TRACE, "couldn't allocate address"); goto error; badprim: err = -EMSGSIZE; mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; outstate: err = TOUTSTATE; mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; notsupport: err = TNOTSUPPORT; mi_strlog(q, 0, SL_TRACE, "primitive not supported for T_CLTS"); goto error; error: return t_error_ack(mtp, q, mp, p->PRIM_type, err);}/** * t_conn_res: - process T_CONN_RES primtive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_conn_res(struct mtp *mtp, queue_t *q, mblk_t *mp){ int err; const struct T_conn_res *p = (typeof(p)) mp->b_rptr; if (mtp->prot.SERV_type == T_CLTS) goto notsupport; if (mtp_get_state(mtp) != TS_WRES_CIND) goto outstate; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; /* We never give an T_CONN_IND, so there is no reason for a T_CONN_RES. We probably could do this (issue an T_CONN_IND on a listening stream when there is no other MTP user for the SI value and * send a UPU on an N_DISCON_REQ or just redirect all traffic for that user on a T_CONN_RES) but that is for later. */ goto eopnotsupp; eopnotsupp: err = -EOPNOTSUPP; mi_strlog(q, 0, SL_TRACE, "operation not supported"); goto error; badprim: err = -EMSGSIZE; mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; outstate: err = TOUTSTATE; mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; notsupport: err = TNOTSUPPORT; mi_strlog(q, 0, SL_TRACE, "primitive not supported for T_CLTS"); goto error; error: return t_error_ack(mtp, q, mp, p->PRIM_type, err);}/** * t_discon_req: - process T_DISCON_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_discon_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ int err; const struct T_discon_req *p = (typeof(p)) mp->b_rptr; if (mtp->prot.SERV_type == T_CLTS) goto notsupport; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; /* Currently there are only three states we can disconnect from. The first does not happen. Only the second one is normal. The third should occur during simulteneous switch (mtp_get_state(mtp)) { case TS_WCON_CREQ: mtp_set_state(mtp, TS_WACK_DREQ6); break; case TS_DATA_XFER: mtp_set_state(mtp, TS_WACK_DREQ9); break; case TS_IDLE: rare(); break; default: goto outstate; } /* change state and let mtp_ok_ack do all the work */ return mtp_discon_req(mtp, q, mp, mp->b_cont); badprim: err = -EMSGSIZE; mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; outstate: err = TOUTSTATE; mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; notsupport: err = TNOTSUPPORT; mi_strlog(q, 0, SL_TRACE, "primitive not supported for T_CLTS"); goto error; error: return t_error_ack(mtp, q, mp, p->PRIM_type, err);}/** * t_data_req: - process T_DATA_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_data_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ const struct T_data_req *p = (typeof(p)) mp->b_rptr; size_t dlen = mp->b_cont ? msgdsize(mp->b_cont) : 0; if (mtp->prot.SERV_type == T_CLTS) goto notsupport; if (mtp_get_state(mtp) == TS_IDLE) goto discard; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto einval; if (!mp->b_cont) goto einval; if ((1 << mtp_get_state(mtp)) & ~(TSF_DATA_XFER | TSF_WREQ_ORDREL)) goto outstate; if (dlen == 0 || dlen > mtp->prot.TSDU_size || dlen > mtp->prot.TIDU_size) goto baddata; return mtp_transfer_req(mtp, q, mp, &mtp->dst, mtp->options.mp, mtp->options.sls, mp->b_cont); baddata: mi_strlog(q, 0, SL_TRACE, "bad data size %lu", (ulong) dlen); goto error; outstate: mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; einval: mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; discard: mi_strlog(q, 0, SL_TRACE, "ignore in idle state"); return (0); notsupport: mi_strlog(q, 0, SL_TRACE, "primitive not supported for T_CLTS"); goto error; error: return m_error(mtp, q, mp, EPROTO);}/** * t_exdata_req: - process T_EXDATA_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_exdata_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ (void) mp; return m_error(mtp, q, mp, EPROTO);}/** * t_info_req: - process T_INFO_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_info_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ return mtp_info_req(mtp, q, mp);}/** * t_bind_req:- process T_BIND_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_bind_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ int err; const struct T_bind_req *p = (typeof(p)) mp->b_rptr; struct mtp_addr src; if (mtp_get_state(mtp) != TS_UNBND) goto outstate; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->ADDR_offset + p->ADDR_length) goto badprim; if (p->CONIND_number) goto notsupport; if (!p->ADDR_length) goto noaddr; if (p->ADDR_length < sizeof(src)) goto badaddr; bcopy(mp->b_rptr + p->ADDR_offset, &src, sizeof(src)); /* we don't allow wildcards yet. */ if (src.family != AF_MTP) goto badaddr; if (!src.si || !src.pc) goto noaddr; if (src.si < 3 && mtp->cred.cr_uid != 0) goto acces; mtp_set_state(mtp, TS_WACK_BREQ); return mtp_bind_req(mtp, q, mp, &src, 0); acces: err = TACCES; mi_strlog(q, 0, SL_TRACE, "no permission for address"); goto error; noaddr: err = TNOADDR; mi_strlog(q, 0, SL_TRACE, "couldn't allocate address"); goto error; badaddr: err = TBADADDR; mi_strlog(q, 0, SL_TRACE, "address is invalid"); goto error; notsupport: err = TNOTSUPPORT; mi_strlog(q, 0, SL_TRACE, "primitive not support for T_CLTS"); goto error; badprim: err = -EMSGSIZE; mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; outstate: err = TOUTSTATE; mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; error: return t_error_ack(mtp, q, mp, p->PRIM_type, err);}/** * t_unbind_req: - process T_UNBIND_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_unbind_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ const struct T_unbind_req *p = (typeof(p)) mp->b_rptr; int err; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mtp_get_state(mtp) != TS_IDLE) goto outstate; mtp_set_state(mtp, TS_WACK_UREQ); return mtp_unbind_req(mtp, q, mp); outstate: err = TOUTSTATE; mi_strlog(q, 0, SL_TRACE, "would place i/f out of state"); goto error; badprim: err = -EMSGSIZE; mi_strlog(q, 0, SL_TRACE, "invalid primitive format"); goto error; error: return t_error_ack(mtp, q, mp, p->PRIM_type, err);}/** * t_unitdata_req: - process T_UNITDATA_REQ primitive * @mtp: private structure * @q: active queue * @mp: the message */static inline fastcall __unlikely intt_unitdata_req(struct mtp *mtp, queue_t *q, mblk_t *mp){ const struct T_unitdata_req *p = (typeof(p)) mp->b_rptr; size_t dlen = mp->b_cont ? msgdsize(mp->b_cont) : 0; struct mtp_addr dst; struct mtp_opts opts = { 0L, NULL, }; if (mtp->prot.SERV_type != T_CLTS) goto notsupport; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->DEST_offset + p->DEST_length) goto badprim; if (mtp_get_state(mtp) != TS_IDLE) goto outstate; if (dlen == 0 && !(mtp->prot.PROVIDER_flag & T_SNDZERO)) goto baddata; if (dlen > mtp->prot.TSDU_size || dlen > mtp->prot.TIDU_size) goto baddata; if (mp->b_wptr < mp->b_rptr + sizeof(*p) || mp->b_wptr < mp->b_rptr + p->DEST_offset + p->DEST_length || mp->b_wptr < mp->b_rptr + p->OPT_offset + p->OPT_length) goto badprim; if (!p->DEST_length) goto noaddr; if (p->DEST_length < sizeof(dst)) goto badaddr; bcopy(mp->b_rptr + p->DEST_offset, &dst, sizeof(dst)); if (dst.family != AF_MTP) goto badaddr;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -