stm32 关于ENC28J60TCP和UDP的实现

实现的功能

ARP的实现

首先我们必须明白,我们的ip是自己手动设定的,这时,怎样让别人知道你,就需要ARP,也就是通过ip找mac地址

ICMP的实现

ICMP这里主要是实现了ping命令

此时ip还没有和mac地址关联

那么ping一下,发现了设备

此时,ip和mac关联了

具体操作

通过发送广播,使设备获取到ip

然后,我们使用udp给设备发消息

   

那么tcp也试一下

 

再贴一个网络抓包

最前面三个是三次握手,然后依次是,客户端发数据,服务器应答,然后服务器发数据,客户端应答,来回两次,最后四个就是四次分手了


缺点:不能发送大堆的数据,同时没有做包效验,不过一次传输少量数据还是很不错的!!!!

具体代码实现

1.arp

unsigned int is_arp_ask_pack(unsigned char *buf)
{
	if (buf[ETH_ARP_OPCODE_H_P] == 0x00	&&
			buf[ETH_ARP_OPCODE_L_P] == 0x01)
	{
		/*请求包*/
		if (0 == memcmp(get_arp_dst_ip(buf),ipaddr,4))
		{
			//请求的我的ip
			return 1;
		}
	}
	return 0;
}
//回发响应包,通过ip找mac
void make_arp_answer_from_request(unsigned char *buf)
{
	unsigned char i=0;
    
	//填写包的目的MAC地址以及源MAC地址	
	make_eth(buf); 
    
    //填写ARP响应包的类型
	buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;   //arp 响应
	buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;

    //填写ARP包的目的MAC地址以及源MAC地址
	while(i<6)
	{
        buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];
        buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];
        i++;
	}

    //填写ARP包的目的IP地址以及源IP地址    
	i=0;
	while(i<4)
	{
        buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];
        buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
        i++;
	}
    //发送ARP相应包
	enc28j60PacketSend(42,buf); 
}

2.ICMP

void make_echo_reply_from_request(unsigned char *buf,unsigned  int len)
{
	//填写包的目的MAC地址以及源MAC地址	
	make_eth(buf);
	//填写包的目的IP地址以及源IP地址	
	make_ip(buf);

    //填写ICMP相应包类型
	buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;	  //////回送应答/////

    // we changed only the icmp.type field from request(=8) to reply(=0).
	// we can therefore easily correct the checksum:
	if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
	{
	    buf[ICMP_CHECKSUM_P+1]++;
	}
	buf[ICMP_CHECKSUM_P]+=0x08;

    //发送ICMP响应包
	enc28j60PacketSend(len,buf);
}

3.udp

void make_udp_reply_from_request(unsigned char *buf,unsigned int datalen)
{
	unsigned int i=0;
	unsigned int ck;
	make_eth(buf);
	
	// total length field in the IP header must be set:
	i= IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
	buf[IP_TOTLEN_H_P]=i>>8;
	buf[IP_TOTLEN_L_P]=i;
	make_ip(buf);

	buf[UDP_DST_PORT_H_P]=udp_dst_port >> 8;//buf[UDP_SRC_PORT_H_P];
	buf[UDP_DST_PORT_L_P]=udp_dst_port & 0xff;//buf[UDP_SRC_PORT_L_P];
	buf[UDP_SRC_PORT_H_P]=udp_src_port >> 8;
	buf[UDP_SRC_PORT_L_P]=udp_src_port & 0xff;
	// source port does not matter and is what the sender used.
	// calculte the udp length:
	buf[UDP_LEN_H_P]=datalen>>8;
	buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
	// zero the checksum
	buf[UDP_CHECKSUM_H_P]=0;
	buf[UDP_CHECKSUM_L_P]=0;

	ck=checksum(&buf[IP_SRC_P], 16 + datalen,1);
	buf[UDP_CHECKSUM_H_P]=ck >> 8;
	buf[UDP_CHECKSUM_L_P]=ck & 0xff;

	enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
}

3.TCP

void make_tcphead(unsigned char *buf,unsigned char mss/*设置mss选项*/)
{
	buf[TCP_DST_PORT_H_P]=tcp_dst_port >> 8;
	buf[TCP_DST_PORT_L_P]=tcp_dst_port & 0xff;
	buf[TCP_SRC_PORT_H_P]=tcp_src_port >> 8;
	buf[TCP_SRC_PORT_L_P]=tcp_src_port & 0xff;

	put_int_to_char(&buf[TCP_SEQ_H_P],seqnum);
	put_int_to_char(&buf[TCP_SEQACK_H_P],asknum);
	
	// zero the checksum
	buf[TCP_CHECKSUM_H_P]=0;
	buf[TCP_CHECKSUM_L_P]=0;
	
	// The tcp header length is only a 4 bit field (the upper 4 bits).
	// It is calculated in units of 4 bytes. 
	// E.g 24 bytes: 24/4=6 => 0x60=header len field
	//buf[TCP_HEADER_LEN_P]=(((TCP_HEADER_LEN_PLAIN+4)/4)) <<4; // 0x60
	if (mss)
	{
	    // the only option we set is MSS to 1408:
	    // 1408 in hex is 0x580
	    buf[TCP_OPTIONS_P]=2;
	    buf[TCP_OPTIONS_P+1]=4;
	    buf[TCP_OPTIONS_P+2]=0x05; 
	    buf[TCP_OPTIONS_P+3]=0x80;
	    // 24 bytes:
	    buf[TCP_HEADER_LEN_P]=0x60;
	}
	else
	{
	    // no options:
	    // 20 bytes:
	    buf[TCP_HEADER_LEN_P]=0x50;
	}
}
//连接三次握手时,第二次连接
void make_tcp_synack_from_syn(unsigned char *buf)
{
	unsigned  int ck;
	//填写包的目的MAC地址以及源MAC地址	
	make_eth(buf);
	//计算包的长度
	// total length field in the IP header must be set: 20 bytes IP + 24 bytes (20tcp+4tcp options)
	ck = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
	buf[IP_TOTLEN_H_P]=ck >> 8;
	buf[IP_TOTLEN_L_P]=ck & 0xff;
	//填写包的目的IP地址以及源IP地址	
	make_ip(buf);
	buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;//SYN ACK
	make_tcphead(buf,1/*同步时添加mss信息*/);
	// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + 4 (one option: mss)
	ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
	buf[TCP_CHECKSUM_H_P]=ck>>8;
	buf[TCP_CHECKSUM_L_P]=ck& 0xff;
	// add 4 for option mss:
	
	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
}
//应答包,没有数据
void make_tcp_ack_from_any(unsigned char *buf,unsigned int len/*上个包的数据长度*/)
{
	unsigned  int j;
	make_eth(buf);

	// fill the header:
	buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V;  //ASK
	// if there is no data then we must still acknoledge one packet
	make_tcphead(buf,0); // no options
	
	// total length field in the IP header must be set:
	// 20 bytes IP + 20 bytes tcp (when no options) 
	j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
	buf[IP_TOTLEN_H_P]=j>>8;
	buf[IP_TOTLEN_L_P]=j&0xff;
	make_ip(buf);
	// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
	j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
	buf[TCP_CHECKSUM_H_P]=j>>8;
	buf[TCP_CHECKSUM_L_P]=j&0xff;

    //printf("\n\r神舟III号[%d.%d.%d.%d]发送ACK包响应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
    
	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
}
//此函数必须确保,在make_tcp_ack_from_any()之后调用
void make_tcp_ack_with_data(unsigned char *buf,unsigned int dlen)
{
	unsigned  int j;
	// fill the header:
	// This code requires that we send only one data packet
	// because we keep no state information. We must therefore set
	// the fin here:
	buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V/*有数据*/;
	
	make_tcphead(buf,0);
	// total length field in the IP header must be set:
	// 20 bytes IP + 20 bytes tcp (when no options) + len of data
	j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
	buf[IP_TOTLEN_H_P]=j>>8;
	buf[IP_TOTLEN_L_P]=j&0xff;
	fill_ip_hdr_checksum(buf);
	// zero the checksum
	buf[TCP_CHECKSUM_H_P]=0;
	buf[TCP_CHECKSUM_L_P]=0;
	// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
	j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2);
	buf[TCP_CHECKSUM_H_P]=j>>8;
	buf[TCP_CHECKSUM_L_P]=j& 0xff;
	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf);
}
//此函数必须确保,在make_tcp_ack_from_any()之后调用
void make_tcp_ack_from_finish(unsigned char *buf)
{
	unsigned  int j;
	// fill the header:
	// This code requires that we send only one data packet
	// because we keep no state information. We must therefore set
	// the fin here:
	buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V;
	
	// total length field in the IP header must be set:
	// 20 bytes IP + 20 bytes tcp (when no options) + len of data
	j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
	buf[IP_TOTLEN_H_P]=j>>8;
	buf[IP_TOTLEN_L_P]=j&0xff;
	fill_ip_hdr_checksum(buf);
	// zero the checksum 
	buf[TCP_CHECKSUM_H_P]=0;
	buf[TCP_CHECKSUM_L_P]=0;
	// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
	j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
	buf[TCP_CHECKSUM_H_P]=j>>8;
	buf[TCP_CHECKSUM_L_P]=j& 0xff;
	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
}

unsigned int check_tcp_udp(unsigned char *buf,unsigned int len)
{
	switch(check_packet_type(buf,len))
	{
	case TYPE_ARP:
		//printf("this is a arp\n");
		if (is_arp_ask_pack(buf))
		{
//			printf("arp:src-->[%d.%d.%d.%d]\n",get_arp_src_ip(buf)[0],get_arp_src_ip(buf)[1],
//							get_arp_src_ip(buf)[2],get_arp_src_ip(buf)[3]);
//			printf("arp:dst-->[%d.%d.%d.%d]\n",get_arp_dst_ip(buf)[0],get_arp_dst_ip(buf)[1],
//								get_arp_dst_ip(buf)[2],get_arp_dst_ip(buf)[3]);
			make_arp_answer_from_request(buf);
		}
		break;
	case TYPE_ICMP:
		//printf("this is a icmp\n");
		if (is_icmp_ask_pack(buf))
		{
			make_echo_reply_from_request(buf,len);
		}
		break;
	case TYPE_TCP:
		//printf("this is a tcp\n");
		return 1;
	case TYPE_UDP:
		//printf("this is a udp\n");
		return 1;
	case TYPE_NONE:
	default:
	}
	return 0;
}

好了,此程序根据神州III源程序更改而成,去除了http协议





发布了34 篇原创文章 · 获赞 5 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览