⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tp_output.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
 * * 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 + -