void tcp_send_packet (
BYTE *rxtx_buffer, //发送缓冲区
WORD_BYTES dest_port, // 目标端口号
WORD_BYTES src_port, // 源端口号
BYTE flags, // TCP标志 FIN SYN ACK
BYTE max_segment_size, // 初始化序号 接收SYN时使用
BYTE clear_seqack, // 设置确认号为0 发送SYN时使用
WORD next_ack_num, // 在上一个数据包序号的基础上累加
WORD dlength, // 负载长度
BYTE *dest_mac, // 目标MAC地址
BYTE *dest_ip ) // 目标IP地址
{
BYTE i, tseq;
WORD_BYTES ck;
// 生成以太网报文头
eth_generate_header ( rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
// 计算数据包 确认号 next_ack_num为累加值
// 1.确认号因等于上一个数据包的序号加上数据包长度
// 2.序号等于上一个数据包的确认号
// 3.FIN和SYN各占一个序号
// 4.确认号和序号使用大端模式,即高地址存放低位数据
// 5.确认号修改发生在三种情况,接收到SYN,接收到FIN,接收到负载数据
if ( next_ack_num )
{
for( i = 4 ; i > 0; i-- )
{
// 取出上一个数据包的序号,累加next_ack_num
next_ack_num = rxtx_buffer [ TCP_SEQ_P + i - 1] + next_ack_num;
// 取出上一个数据包的确认号
tseq = rxtx_buffer [ TCP_SEQACK_P + i - 1];
// 复制本次数据包的确认号,即上个数据包的序号+next_ack_num
rxtx_buffer [ TCP_SEQACK_P + i - 1] = 0xff & next_ack_num;
// 复制上一个数据包的确认号于本数据包的序号
rxtx_buffer[ TCP_SEQ_P + i - 1 ] = tseq;
next_ack_num >>= 8;
}
}
// 初始化序号
// 设置最大分片
// 第一次发送或接收时使用
if ( max_segment_size )
{
// 初始化序号
rxtx_buffer[ TCP_SEQ_P + 0 ] = 0;
rxtx_buffer[ TCP_SEQ_P + 1 ] = 0;
rxtx_buffer[ TCP_SEQ_P + 2 ] = seqnum;
rxtx_buffer[ TCP_SEQ_P + 3 ] = 0;
seqnum += 2;
// 初始化 报文段最大长度
rxtx_buffer[ TCP_OPTIONS_P + 0 ] = 2; // 最大报文长度
rxtx_buffer[ TCP_OPTIONS_P + 1 ] = 4; // TCP选项长度 TCP选项格式2
rxtx_buffer[ TCP_OPTIONS_P + 2 ] = HIGH(1408); //
rxtx_buffer[ TCP_OPTIONS_P + 3 ] = LOW(1408); //
// 数据偏移,占用高4位,且计算长度为双字
rxtx_buffer[ TCP_HEADER_LEN_P ] = 0x60;
dlength += 4;
}
else
{
// 没有TCP选项时长度为5个双字
rxtx_buffer[ TCP_HEADER_LEN_P ] = 0x50;
}
// generate ip header and checksum
ip_generate_header ( rxtx_buffer, (WORD_BYTES){(IP_HEADER_LEN + TCP_HEADER_LEN + dlength)}, IP_PROTO_TCP_V, dest_ip );
// 清除序号,一般使用于发送SYN时
if ( clear_seqack )
{
rxtx_buffer[ TCP_SEQACK_P + 0 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 1 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 2 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 3 ] = 0;
}
// 设置TCP标志
rxtx_buffer [ TCP_FLAGS_P ] = flags;
// 设置目标端口号
rxtx_buffer [ TCP_DST_PORT_H_P ] = dest_port.byte.high;
rxtx_buffer [ TCP_DST_PORT_L_P ] = dest_port.byte.low;
// 设置源端口号
rxtx_buffer [ TCP_SRC_PORT_H_P ] = src_port.byte.high;
rxtx_buffer [ TCP_SRC_PORT_L_P ] = src_port.byte.low;
// 设置TCP窗口大小
rxtx_buffer [ TCP_WINDOWSIZE_H_P ] = HIGH((MAX_RX_BUFFER-IP_HEADER_LEN-ETH_HEADER_LEN));
rxtx_buffer [ TCP_WINDOWSIZE_L_P ] = LOW((MAX_RX_BUFFER-IP_HEADER_LEN-ETH_HEADER_LEN));
// 紧急指针
rxtx_buffer[ TCP_URGENT_PTR_H_P ] = 0;
rxtx_buffer[ TCP_URGENT_PTR_L_P ] = 0;
// 计算校验和
rxtx_buffer[ TCP_CHECKSUM_H_P ] = 0;
rxtx_buffer[ TCP_CHECKSUM_L_P ] = 0;
ck.word = software_checksum( &rxtx_buffer[IP_SRC_IP_P], TCP_HEADER_LEN+dlength+8, IP_PROTO_TCP_V + TCP_HEADER_LEN + dlength );
rxtx_buffer[ TCP_CHECKSUM_H_P ] = ck.byte.high;
rxtx_buffer[ TCP_CHECKSUM_L_P ] = ck.byte.low;
// 通过enc28j60发送数据
enc28j60_packet_send ( rxtx_buffer, ETH_HEADER_LEN+IP_HEADER_LEN+TCP_HEADER_LEN+dlength );
}