📄 tp_output.c
字号:
* * SIDE EFFECTS: * * NOTES: */ProtoHook tp_ctloutput(cmd, so, level, optname, mp) int cmd, level, optname; struct socket *so; struct mbuf **mp;{ struct tp_pcb *tpcb = sototpcb(so); int s = splnet(); caddr_t value; unsigned val_len; int error = 0; IFTRACE(D_REQUEST) tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", cmd, so, optname, mp); ENDTRACE IFDEBUG(D_REQUEST) printf( "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", so, cmd, optname, mp, mp?*mp:0, tpcb); ENDDEBUG if( tpcb == (struct tp_pcb *)0 ) { error = ENOTSOCK; goto done; } if(*mp == MNULL) { register struct mbuf *m; MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ if (m == NULL) { splx(s); return ENOBUFS; } m->m_len = 0; m->m_act = 0; *mp = m; } /* * Hook so one can set network options via a tp socket. */ if ( level == SOL_NETWORK ) { if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) error = ENOTSOCK; else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) error = EOPNOTSUPP; else return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, tpcb->tp_npcb, *mp)); goto done; } else if ( level == SOL_SOCKET) { if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { u_long old_credit = tpcb->tp_maxlcredit; tp_rsyset(tpcb); if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat && tpcb->tp_state == TP_OPEN && (old_credit < tpcb->tp_maxlcredit)) tp_emit(AK_TPDU_type, tpcb, tpcb->tp_rcvnxt, 0, MNULL); tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; } goto done; } else if ( level != SOL_TRANSPORT ) { error = EOPNOTSUPP; goto done; } if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { error = EOPNOTSUPP; goto done; } if ( so->so_error ) { error = so->so_error; goto done; } /* The only options allowed after connection is established * are GET (anything) and SET DISC DATA and SET PERF MEAS */ if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) && (cmd == PRCO_SETOPT && optname != TPOPT_DISC_DATA && optname != TPOPT_CFRM_DATA && optname != TPOPT_PERF_MEAS && optname != TPOPT_CDDATA_CLEAR ) ) { error = EISCONN; goto done; } /* The only options allowed after disconnection are GET DISC DATA, * and TPOPT_PSTATISTICS * and they're not allowed if the ref timer has gone off, because * the tpcb is gone */ if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { if ( so->so_pcb == (caddr_t)0 ) { error = ENOTCONN; goto done; } if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { error = ENOTCONN; goto done; } } value = mtod(*mp, caddr_t); /* it's aligned, don't worry, * but lint complains about it */ val_len = (*mp)->m_len; switch (optname) { case TPOPT_INTERCEPT:#define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)#define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) if ((so->so_state & SS_PRIV) == 0) { error = EPERM; } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || (tpcb->tp_flags & TPF_GENERAL_ADDR) || tpcb->tp_next == 0) error = EINVAL; else { register struct tp_pcb *t; error = EADDRINUSE; for (t = tp_listeners; t; t = t->tp_nextlisten) if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && t->tp_domain == tpcb->tp_domain) switch (tpcb->tp_domain) { default: goto done;#ifdef INET case AF_INET: if (INA(t) == INA(tpcb)) goto done; continue;#endif#ifdef ISO case AF_ISO: if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, ISOA(t).isoa_len) == 0) goto done; continue;#endif } tpcb->tp_lsuffixlen = 0; tpcb->tp_state = TP_LISTENING; error = 0; remque(tpcb); tpcb->tp_next = tpcb->tp_prev = tpcb; tpcb->tp_nextlisten = tp_listeners; tp_listeners = tpcb; } break; case TPOPT_MY_TSEL: if ( cmd == PRCO_GETOPT ) { ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); (*mp)->m_len = tpcb->tp_lsuffixlen; } else /* cmd == PRCO_SETOPT */ { if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); error = EINVAL; } else { bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); tpcb->tp_lsuffixlen = val_len; } } break; case TPOPT_PEER_TSEL: if ( cmd == PRCO_GETOPT ) { ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); (*mp)->m_len = tpcb->tp_fsuffixlen; } else /* cmd == PRCO_SETOPT */ { if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); error = EINVAL; } else { bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); tpcb->tp_fsuffixlen = val_len; } } break; case TPOPT_FLAGS: IFDEBUG(D_REQUEST) printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", cmd==PRCO_GETOPT?"GET":"SET", value, *value, tpcb->tp_flags); ENDDEBUG if ( cmd == PRCO_GETOPT ) { *(int *)value = (int)tpcb->tp_flags; (*mp)->m_len = sizeof(u_int); } else /* cmd == PRCO_SETOPT */ { error = EINVAL; goto done; } break; case TPOPT_PARAMS: /* This handles: * timer values, * class, use of transport expedited data, * max tpdu size, checksum, xtd format and * disconnect indications, and may get rid of connect/disc data */ IFDEBUG(D_SETPARAMS) printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, cmd==PRCO_GETOPT?"GET":"SET"); ENDDEBUG IFDEBUG(D_REQUEST) printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, cmd==PRCO_GETOPT?"GET":"SET"); ENDDEBUG if ( cmd == PRCO_GETOPT ) { *(struct tp_conn_param *)value = tpcb->_tp_param; (*mp)->m_len = sizeof(tpcb->_tp_param); } else /* cmd == PRCO_SETOPT */ { if( (error = tp_consistency(tpcb, TP_STRICT | TP_FORCE, (struct tp_conn_param *)value))==0) { /* * tp_consistency doesn't copy the whole set of params */ tpcb->_tp_param = *(struct tp_conn_param *)value; (*mp)->m_len = sizeof(tpcb->_tp_param); } } break; case TPOPT_PSTATISTICS: #ifdef TP_PERF_MEAS if (cmd == PRCO_SETOPT) { error = EINVAL; goto done; } IFPERF(tpcb) if (*mp) { struct mbuf * n; do { MFREE(*mp, n); *mp = n; } while (n); } *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); ENDPERF else { error = EINVAL; goto done; } break;#else error = EOPNOTSUPP; goto done;#endif /* TP_PERF_MEAS */ case TPOPT_CDDATA_CLEAR: if (cmd == PRCO_GETOPT) { error = EINVAL; } else { if (tpcb->tp_ucddata) { m_freem(tpcb->tp_ucddata); tpcb->tp_ucddata = 0; } } break; case TPOPT_CFRM_DATA: case TPOPT_DISC_DATA: case TPOPT_CONN_DATA: if( tpcb->tp_class == TP_CLASS_0 ) { error = EOPNOTSUPP; break; } IFDEBUG(D_REQUEST) printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", (*mp)->m_len, val_len, so->so_snd.sb_cc); dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); ENDDEBUG if (cmd == PRCO_SETOPT) { int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; /* can append connect data in several calls */ if (len + val_len > (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { error = EMSGSIZE; goto done; } (*mp)->m_next = MNULL; (*mp)->m_act = 0; if (tpcb->tp_ucddata) m_cat(tpcb->tp_ucddata, *mp); else tpcb->tp_ucddata = *mp; IFDEBUG(D_REQUEST) dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); ENDDEBUG IFTRACE(D_REQUEST) tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); ENDTRACE *mp = MNULL; if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) (void) tp_confirm(tpcb); } break; case TPOPT_PERF_MEAS: #ifdef TP_PERF_MEAS if (cmd == PRCO_GETOPT) { *value = (u_int)tpcb->tp_perf_on; (*mp)->m_len = sizeof(u_int); } else if (cmd == PRCO_SETOPT) { (*mp)->m_len = 0; if ((*value) != 0 && (*value) != 1 ) error = EINVAL; else tpcb->tp_perf_on = (*value); } if( tpcb->tp_perf_on ) error = tp_setup_perf(tpcb);#else /* TP_PERF_MEAS */ error = EOPNOTSUPP;#endif /* TP_PERF_MEAS */ break; default: error = EOPNOTSUPP; } done: IFDEBUG(D_REQUEST) dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); dump_mbuf(*mp, "tp_ctloutput *mp"); ENDDEBUG /* * sigh: getsockopt looks only at m_len : all output data must * reside in the first mbuf */ if (*mp) { if (cmd == PRCO_SETOPT) { m_freem(*mp); *mp = MNULL; } else { ASSERT ( m_compress(*mp, mp) <= MLEN ); if (error) (*mp)->m_len = 0; IFDEBUG(D_REQUEST) dump_mbuf(*mp, "tp_ctloutput *mp after compress"); ENDDEBUG } } splx(s); return error;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -