当前位置:   article > 正文

基于STM32&lwip实现ping命令_lwip ping

lwip ping

Ping命令实现之Lwip—基于stm32F103

1、Ping命令原理

​ ping命令属于Network layerICMP(Internet control massage protol)协议构成,ICMP报文可以分为两大类:

ICMP报文种类type功能*
错误报告报文3目的站不可达
4源站抑制
5重定向(改变路由)
11数据包超时
12数据包参数错误
查询报文0/8会话请求或回答
9/10路由器询问或通告
13/14时间戳请求或回答
15/16信息请求或回答
17/18地址掩码请求或回答

ICMP报文格式

在这里插入图片描述

在这里插入图片描述

Ping 命令在ICMP报文中的类型

ping命令主要是用来测试两个IP地址之间的网络是否能够连通,确定具有一条通路。在Windows 控制台中我们可以使用Ping命令来测试我们的主机是否能与其他主机通信,格式如下:

ping xxx.xxx.xxx.xxx(dest IP_addr)
  • 1

​ 在测试TCP/IP协议栈是否移植成功时,一个简便的方法就是测试 ping命令是否能够应答成功,效果如下:
在这里插入图片描述

Ping命令的帧格式

​ 先给出ping命令的帧格式

在这里插入图片描述

  • type:指ICMP报文的类型,例如ICMP两大类报文:差错报告报文和查询报文,其中含有许多不同类型的功能报文,因此对其分类。
  • code:对于每种不同类型(type)的报文在又含有不同的编码信息,例如差错报告报文中的数据包超时报文,就可分为两种:数据包分片超时和TTL超时。
  • Identifier:标识符,没有指明其正式定义,可自行定义。
  • Seq number:序列号,没有正式指明其定义,可自行定义。

2、代码设计

MCU启动Ping数据包接收或发送

void Ping_Init(void)
{
#if FUNC_DBG_ON        
    printf("run in %s .\r\n",__FUNCTION__);
#endif     
    IP4_ADDR(&dest_ip,192,168,1,31);
    IP4_ADDR(&local_ip,192,168,1,10);
    /*bind local IP.*/
    printf("local IP address:%4d.%4d.%4d.%4d\r\n",ip4_addr1(&local_ip),\
                                                    ip4_addr2(&local_ip),\
                                                    ip4_addr3(&local_ip),\
                                                    ip4_addr4(&local_ip));
    /*bind dest IP.*/
    printf("dest IP address:%4d.%4d.%4d.%4d\r\n", ip4_addr1(&dest_ip),\
                                                    ip4_addr2(&dest_ip),\
                                                    ip4_addr3(&dest_ip),\
                                                    ip4_addr4(&dest_ip));    
    /*allocate a new pcb*/
    ping_pcb = raw_new(IP_PROTO_ICMP);//set IP protocol type to ICMP
    if(NULL == ping_pcb) {
        printf("get n new raw pcb failed.\r\n");
        return;
    }
    
    PingCmd_start(ping_pcb);
}

void PingCmd_start(struct raw_pcb *pcb)
{
#if FUNC_DBG_ON        
    printf("run in %s .\r\n",__FUNCTION__);
#endif   
    raw_bind(pcb,&local_ip);//bind local IP to pcb.
  //  raw_connect(pcb,&dest_ip);
    raw_recv(pcb,recv_callback,NULL);
   // ping_cnt--; 
    /*sys_timeout()为注册一个单次定时事件,当计时结束后,会主动发送REQUEST包,PC会给予响应 
    * 接收Ping命令时关闭,MCU发起ping请求时打开。
    */
   //  sys_timeout(PING_DELAY,timeoutHandle,pcb);//set a oneshot time event for periodicly.
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

MCU接收数据

Windows终端对MCU已设置好的IP地址进行ping命令调试,PC端发出的ICMP报文中type应为0x08code0x00,identifierseq number可随意指定,故在MCU端接收代码可设置为如下格式:

u8_t recv_callback(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
{                   //  p->payload point the IP header/Ethernet frame data field.

    struct icmp_echo_hdr *icmp_hdr = NULL;
    struct ip_hdr *ip_hdr = NULL;
    u8_t ip_hlen = 0;
    u8_t *data_ptr = NULL;
#if FUNC_DBG_ON        
    printf("run in %s .\r\n",__FUNCTION__);
#endif     		
		(void)arg;
    if(ip_addr_cmp(&dest_ip,addr) &&\
         p->tot_len > (IP_HLEN + sizeof(struct icmp_echo_hdr)))//process packet
    {
        ip_hdr = (struct ip_hdr *)p->payload; //point to IP header
        ip_hlen = IPH_HL(ip_hdr)*4;           //1 len means 4 bytes.

        //adjust p->payload point ICMP header.
        if(pbuf_header(p,-ip_hlen))
            printf("Adjust header failed.\r\n");
        icmp_hdr = (struct icmp_echo_hdr *)p->payload;
        if(0x00 == icmp_hdr->code)
        {
            data_ptr = (u8_t*)p->payload + sizeof(struct icmp_echo_hdr);
            printf("icmp_hdr->type %d .\r\n",icmp_hdr->type);            
            switch (icmp_hdr->type)
            {
            case PING_REPLY:    //receive a reply message.
                printf("[Receive message]:%s.\r\n",data_ptr);
                printf("[ID]:%x.\r\n",icmp_hdr->id);
                printf("[SEQ Number]:%x.\r\n",icmp_hdr->seqno);   
                sys_timeout(PING_DELAY,timeoutHandle,pcb);//continue to send a ping REQUEST packet.           
                break;
            case PING_REQUEST:  //need ack
                printf("Receive a REQUEST message.\r\n");
                printf("[Receive message]:%s.\r\n",data_ptr);
                printf("[ID]:%x.\r\n",icmp_hdr->id);
                printf("[SEQ Number]:%x.\r\n",icmp_hdr->seqno); 

                /*change type,reset checksum*/
                ICMPH_TYPE_SET(icmp_hdr,PING_REPLY);//set type.
                /*checksum*/
                if(icmp_hdr->chksum >= htons(0xffffU - (PING_REQUEST<<8)))
                    icmp_hdr->chksum +=htons(PING_REQUEST<<8 + 1);
                else
                    icmp_hdr->chksum +=htons(PING_REQUEST<<8);
                raw_sendto(pcb,p,addr);

                break;
            
            default:
                break;
            }  
        }
        else
            printf("[ERROR]:It's not a ping format packet.\r\n");
    }
    pbuf_free(p);
    return 1;//delete pbuf.
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

该代码块流程如下:
在这里插入图片描述

从代码块中可以看出,在处理接收pbuf时与发送pbuf时不同。发送时申请的pbuf为IP层pbuf模型,Lwip默认将IP首部预留给底层函数添加其信息,而payload指针直接指向其数据区;接收时,下层处理函数直接将完整的pbuf数据包传递给pcb控制块,关于为何没有直接将payload指向IP数据区,有待研究。

PC发送ping命令REQUEST包—Wireshark抓包测试

  • PC端IP:192.168.1.31
  • MCU端IP:192.168.1.10

PC终端发起ping请求:

在这里插入图片描述

WireShark抓包结果

在这里插入图片描述

MCU发起Ping请求

​ ping数据区域值为This a ping test,only for REQUSET message.,由于MCU是在上电启动后自动执行ping命令,直接给出WireShark抓包结果。

在这里插入图片描述

查看数据是否正确

在这里插入图片描述

从结果来看,PC端正确接收数据,至此关于MCU发起、接收ping命令结束,当然,MCU程序设计还有些许不足,没有对ping包进行数量限制,而是持续发送。


工程源码

链接:https://pan.baidu.com/s/1ez-gm1TW0rLBo6xK2aNGFA?pwd=lfds
提取码:lfds

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/972290
推荐阅读
相关标签
  

闽ICP备14008679号