ARM技术论坛
直播中

黄欢

13年用户 61经验值
擅长:可编程逻辑 控制/MCU
私信 关注
[经验]

让你的电路板接入互联网—UIP协议移植与漏洞修复(带视频)

` 本帖最后由 ruihuan 于 2018-1-31 15:31 编辑

       今天开始,我将陆续分享arm m0 平台下的UIP协议栈的移植经验。请各位多多指教。
       作为一个电子工程师,想必“接入互联网”这个想法,是非常具有吸引力的。但是,很多电路板上的资源实在是非常有限,要把一个完整的操作系统移植进去,对于很多电路板来说这是一件不可能的事情。所以这种情况下,我们只能选择轻量级的协议栈进行移植。这类协议栈有很多,在这里我选择“UIP”。而驱动芯片选择的是“ENC28J60”,因为这款芯片用的通信接口是SPI接口,可以节省很多芯片的引脚,对于通信数据量不大的场合是足够应付了。MCU选择的是LPC1114,是一款arm m0 内核的芯片,这款芯片的资源足够做很多应用了。这款芯片网上应用的资料还是比较多的,比较方便学习,用这芯片做SD,TFT小屏这类应用还是蛮多的,但是互联网功能的资料好、还是比较少的。
      第一个贴先介绍基本情况,往后将陆续更新,敬请关注!
  
第一讲:基本移植:
https://bbs.elecfans.com/jishu_473925_1_1.html审核审那么久。。。。到百度文库那里吧。。。
wenku.baidu.com/view/2a8aecfad4d8d15abf234e07
视频

[media]v.youku.com/v_show/id_XOtixOTQ1MjIw.html[/media]

`

回帖(18)

黄欢

2015-3-28 14:16:00
一、uip协议移植第一讲:
下载的协议包,文件目录如下:
image001.png
移植过程:
1、将uip文件里的所有文件添加到工程内;
2、将Unix文件内的文件拷贝出来并且进行修改;
image003.png
tapdev.c文件有添加或者修改的函数:
void tapdev_init(void) 网络模块的初始化函数
unsigned int tapdev_read(void) 读数据函数,添加网络模块的读缓存数据的函数
void tapdev_send(void) 网络模块发送数据
发送数据和接收数据都通过全局变量:
uip_buf :数据缓存
uip_len :数据长度
clock-arch.c 文件修改
clock_time_t clock_time(void) 返回没10ms加1的数据。这我用的是定时中断10ms全局变量加1,然后函数返回全局变量。
修改和配置文件uip-conf.h
//最大TCP连接数
#define UIP_CONF_MAX_CONNECTIONS 40
//最大TCP端口监听数
#define UIP_CONF_MAX_LISTENPORTS 40
//uIP缓存大小
#define UIP_CONF_BUFFER_SIZE    4096  //注:这里应该设置的数值不能大于驱动最大发送字节的数值(如果用ENC28J60的话,应该不能大于1518)
//CPU大小端模式
//小端模式的
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
//日志开关
#define UIP_CONF_LOGGING        0
//UDP支持开关
#define UIP_CONF_UDP            0
//UDP校验和开关
#define UIP_CONF_UDP_CHECKSUMS  1      
//uIP统计开关  
#define UIP_CONF_STATISTICS     1                                                  
#include "MY_APPCall.h"//这个是用的回调函数的文件的头文件,跟据用的实际情况而修改。但这个一定不能漏。因为这问还要定义两个比较中要的变量。
在用户回调函数文件的头件定义两个变量:
//定义uip_tcp_appstate_t 数据类型,用户可以添加应用程序需要用到
//成员变量。不要更改结构体类型的名字,因为这个类型名会被uip引用。
//uip.h 中定义的   structuip_conn  结构体中引用了uip_tcp_appstate_t         
struct tcp_demo_appstate
{
     uint8 state;
     uint8 *textptr;
     inttextlen;
};
typedef struct tcp_demo_appstateuip_tcp_appstate_t;
void MY_APPCall(void);
//定义应用程序回调函数
#ifndef UIP_APPCALL
#define UIP_APPCALL MY_APPCall //定义回调函数为tcp_demo_appcall
注意:MY_APPCall 为回调函数。所有的数据处理都在这个函数中完成。而不是在main函数中完成的。

3、最后修改工程配置,将uip-conf.h所在文件路径和uip路径加到工程的编译头文件路径中。

举报

黄欢

2015-3-28 18:55:56
第一讲:uip基本移植;
https://bbs.elecfans.com/jishu_473925_1_1.html
举报

柠檬守护

2015-3-28 23:23:04
支持下楼主呢, 喜欢这个东西,还希望楼主能够多讲点基础的内容啊~ 谢谢楼主
举报

黄欢

2015-3-29 10:10:41
引用: 柠檬守护 发表于 2015-3-28 23:23
支持下楼主呢, 喜欢这个东西,还希望楼主能够多讲点基础的内容啊~ 谢谢楼主 ...

谢谢你的支持。我将陆续更新相关内容。敬请关注!
举报

柠檬守护

2015-3-30 09:45:08
引用: ruihuan 发表于 2015-3-29 10:10
谢谢你的支持。我将陆续更新相关内容。敬请关注!

那是自然,顺便提一下,二楼的那个地址,无法打开了。
举报

黄欢

2015-4-2 10:29:15
第二讲:UIP应用编程:
IMG_20150401_200107.jpg


        首先连接好你的电路板,仿真线和网线(呵呵。。。感觉是废话,但是我还是比较任性的要讲)
       接着就开始编程了。如果你有socket的应用编程经验的话,UIP的应用编程也差不多的,操作步骤都是一样的。以电路板做服务端为例:设地址、设监听端口、启动监听、等待连接、接收或者发送数据、关闭连接。这些过程都是一样的。但是,如果你要想直接这样掉用接口,肯定是不行的。因为这样子的话,UIP协议栈就没有办法运行部起来了。所以,你的应用编程必须要在他的框架内来编程。因此有几个要注意的地方:
1、uip_polling();这个函数一定要保证其一直在不断的运行,因为这函数是让UIP协议栈核心代码运行的循环函数,如果它不运行了,UIP协议栈也不运行了。毕竟UIP并没有真正的多任务操作系统的内核,如果像是有多任务操作系统内核的协议栈只要把协议栈运行起来后,这类协议栈将自己调用操作系统任务来完成对应的操作,因而通常这个函数是放在main函数的while死循环里。
2、UIP协议栈提供了一个回调的接口函数,基本上以太网的所有的消息都会触发这个回调函数,因而你也可以认为这个UIP协议栈提供出来的编程接口,几乎所有用户应用编程都在这里编写。
3、UIP协议栈TCP不能主动触发数据发送函数,只能被动触发数据发送。因而,发送数据仅能在你定义的回调函数中执行。如果你想让其具有主动发送数据的功能,下一讲告诉你解决方法。
视频教程网址:
   v.youku.com/v_show/id_XOTI1MTczMDky.html
最后,UIP协议栈被动断开TCP连接是有问题的,断开后要等待一段时间后才能重新连接。这个下一讲再讲。

敬请等待下一讲,UIP协议漏洞与修复。下一讲更精彩哦~
举报

黄欢

2015-4-2 10:30:50
第二讲 UIP应用编程
网址:v.youku.com/v_show/id_XOTI1MTczMDky.html
举报

黄欢

2015-4-2 10:31:53
第二讲的内容在审核中。。。。
举报

柠檬守护

2015-4-2 13:57:23
谢谢楼主的分享啊~
举报

vvg

2015-4-3 10:28:51
引用: ruihuan 发表于 2015-4-2 10:31
第二讲的内容在审核中。。。。

已处理

举报

freewind1949

2015-4-10 14:28:59
代码写的,看着很舒服,感谢分享
举报

黄欢

2015-4-14 16:18:05
第三讲:UIP漏洞修复

一、在讲UIP协议桟漏洞修复之前,先介绍一下UIP协议栈的信息处理流程:
image002.gif
在这里我们看有的重要的东西:结构题数组 uip_conn。这个数组记录每一个有效的连接的所需要的重要信息。具体的内容如下:


struct uip_conn {
  uip_ipaddr_t ripaddr;   /**< The IPaddress of the remote host. */
  
  u16_t lport;        /**< Thelocal TCP port, in network byte order. */
  u16_t rport;        /**< Thelocal remote TCP port, in network byte
               order. */
  
  u8_t rcv_nxt[4];    /**< Thesequence number that we expect to
               receive next. */
  u8_t snd_nxt[4];    /**< Thesequence number that was last sent by
                        us. */
  u16_t len;          /**
  u16_t mss;          /**
               connection. */
  u16_t initialmss;   /**< Initialmaximum segment size for the
               connection. */
  u8_t sa;            /**
               variable. */
  u8_t sv;            /**
               variable. */
  u8_t rto;           /**
  u8_t tcpstateflags; /**< TCP state and flags. */
  u8_t timer;         /**< Theretransmission timer. */
  u8_t nrtx;          /**< Thenumber of retransmissions for the last
               segment sent. */
  /** Theapplication state. */
  uip_tcp_appstate_t appstate;
};


我们可以看到每建立一个连接都会保存对应的一组信息。而每一个数据包里的SQE的信息是个判断对应着哪个数据包的重要数据。如果不用一个数组来记录这些信息,当前仅仅能建立一组信息。
经过以上分析,我们可以知道。如果需要修改UIP协议栈,要注意两点:
1、 在拆包过程中能找到我们想要处理的信息位置。
2、 修改过程中要注意是否有妨碍其记录struct uip_conn 数组的信息。如果要主动发送数据,必须从这个结构体数组中获取到对应的信息。例如,添加主动发送的函数就是在这个数组中取到对应的信息来构建数据包的。
二、修改断开TCP连接的漏洞:
问题情况描述:
       “板子”这一端作为服务端、电脑软件这端作为客户端。当客户端要断掉TCP连接的时候,可以断开。但是,断掉连接之后却不能马上连接回去,要等待至少半分钟左右才能重新连接上。
       抓包分析:电路板这一端仅仅是发送送“FIN”这这一帧数据而已,但是按照原理上来说:端口连接的时候,应该返回的有两个数据帧才对的(FIN数据帧和ACK数据帧)。
修改:
       uip.c文件中找到标号“tcp_send_finack: 注释掉原来的 goto tcp_send_nodata;
换成 BE_Closed_FIN_Back();
BE_Closed_FIN_Back(); 是我新写的一个函数,完成断开TCP连接之后发送“FIN”和“ACK”数据包的功能。
UIP 1
image006.png
image008.png
image010.png
新添加的函数在一下位置调用
image012.png
三、决解UIP TCP不能主动发数据的问题
添加发送数据函数:void send_TCP_data(const void *dat, int len);
这个函数是通用过记录的 structuip_conn 数组的信息 来重新构建数据包,来达到主动发数据的作用。但是,UIP协议栈本身没有对已经连接的数据进行区别判断记录,并且这个函数发送数据的时候没有具体的连接判断,所以当调用这个函数的时候,当前的所有连接的都会发送数据。
image014.png
image016.png
image018.png


×
20
完善资料,
赚取积分