当前位置:
文档之家› uip协议栈uip_process函数工作流程详解
uip协议栈uip_process函数工作流程详解
found: (1)若接收到的是 RST 数据包,则将本连接状态置为 UIP_CLOSED,uip_flags = UIP_ABORT;, 调用 UIP_APPCALL()通知应用程序处理连接断开请求。然后丢弃此包,直接返回; (2)检查接收到的数据包中的数据编号是否为自己等在等待的数据编号,若不是则 goto tcp_send_ack;发送自己期望的数据编号的数据,即请求重传。若是则继续向下; (3)检查接收到的数据包中是否包含 ACK,
if(uip_outstanding(uip_connr)&&(timer-- == 0)) 已经发送的数据包还未接收 到对其的 ACK,超时计数器减一且超时计数器值为 0
{ ①如果到达所设定的重发次数则:
1、tcpstateflags = UIP_CLOSED;关闭当前连接 2、uip_flags = UIP_TIMEDOUT;通知应用程序超时; 3、UIP_APPCALL(); 4、设置 RST+ACK 终止连接标志 5、goto tcp_send_nodata; ②没有到达设定的重发次数则重传数据: 1、重置重传计数器 2、 switch(tcpstateflags)根据连接处的不同状态重发不同的数据包
———————————————————————————————————————
tcp_input: (1)检查 TCP 校验和,若正确向下继续,若错误则丢弃此包直接返回; (2)在 TCP 连接列表 uip_conns 中轮询,检查接收到的 TCP 数据包是否已经建立连接(通过逐 个比较源端口、目的端口和源 IP 是否与链接列表中的相同)。
(6)if(BUF->proto == UIP_PROTO_UDP)IP 上层协议是否为 UDP 协议 ①是,goto udp_input;进入 UDP 数据处理模块 ②不是,继续向下执行
(7)if(BUF->proto != UIP_PROTO_ICMP) 不是 TCP 不是 UDP 也不是 ICMP 协议
uip_process(u8_t flag) (1)if(flag == UIP_UDP_SEND_CONN),若是则 goto udp_send;不是则向下执行; (2) if(flag == UIP_POLL_REQUEST) {
if(tcpstateflags== UIP_ESTABLISHED &&!uip_outstanding(uip_connr))如果处于稳 定连接状态且没有数据在缓存中等待确认则:
case UIP_SYN_SENT: (1)如果接收到 ACK 且为 SYN+ACK 则:
①检查 TCP 扩展选项,如果有扩展选项从中取出 MSS 信息; ②tcpstateflags = UIP_ESTABLISHED;进入 ESTABLISHED 状态 ③设置接收编号,uip_flags = UIP_CONNECTED | UIP_NEWDATA;调用 UIP_APPCALL()处 理刚建立的连接和新接收到数据; ④goto appsend; (2)没有接收到 ACK 且为 SYN+ACK 则: ①uip_flags = UIP_ABORT;终止连接调用 UIP_APPCALL(); ②tcpstateflags = UIP_CLOSED;关闭 TCP 连接 ③goto reset;
(3)检查 IP 帧头中的 IP 版本及 IP 头长度是否符合要求: ①不符合:goto drop;丢弃此包 ②符合继续向下执行
(4)检查目的 IP 地址是否为本机地址: ①不是,goto drop;丢弃此包 ②是,向下继续执行
(5)if(BUF->proto == UIP_PROTO_TCP)IP 上层协议是否为 TCP 协议 ①是,goto tcp_input;进入 TCP 数据处理模块 ②不是,继续向下执行
apprexmit: (1)如果(uip_slen > 0 && uip_connr->len > 0)则发送 PSH_ACK 数据包; (2)如果(uip_flags & UIP_NEWDATA)仅仅是发送 ACK,没有数据要发送则发送对接收
到数据的 ACK;
(3) goto drop;
case UIP_LAST_ACK: (1)如果 uip_flags & UIP_ACKDATA 接收到对本机发送的 FIN 的 ACK 确认则:
若找到 goto found; 没有找到则检查接收到的 TCP 数据包中是否含有 SYN 请求建立连接标志:
若没有则 goto reset;发送 RST+ACK 断开连接; 若有则检查 uip_listenports 监听列表,若 TCP 数据包目的端口在监听列表中则 goto found_listen;若不在监听列表中则向下执行,进入 reset;发送 RST+ACK 断开连接;
①tcpstateflags = UIP_CLOSED;关闭 TCP 连接; ②发送 RST+ACK 关闭连接; (2)如果(uip_flags & UIP_CLOSE)正常关闭连接则: ①tcpstateflags = UIP_FIN_WAIT_1;进入等待关闭状态 ②发送 FIN+ACK 告知对方关闭连接; (3)如果 uip_slen > 0 有数据要发送则设置发送数据的长度
{ ①uip_flags = UIP_POLL; ②UIP_APPCALL(); ③goto appsend; } goto drop; } else if(flag == UIP_TIMER) {
uip_len = 0; uip_slen = 0; 如果连接处于等待超时关闭状态则增加超时计数器,如果到达超时期限则关闭当前连 接 tcpstateflags = UIP_CLOSED; if(tcpstateflags != UIP_CLOSED) 如果连接不处于关闭状态 {
uip_flags = UIP_CONNECTED;/*连接成功* ②检查数据包长度是否包含数据部分,若是则 uip_flags |= UIP_NEWDATA; ③调用 UIP_APPCALL()处理刚建立的连接和新接收到数据; ⑤goto appsend; 若不是则 goto drop;丢包返回;
若是则: ①更新发送数据序列的编号,使之可以发送后续数据; ②计算 RTT 时间,重新设置 RTT 时间; ③uip_flags = UIP_ACKDATA;表明接收到 ACK ④uip_connr->len = 0;表明等待 ACK 的数据长度为 0,即可以发送其它数据 ⑤继续向下;
若不是:继续向下;
——————————————————————————————————————— udp_input: (1)根据要求校验 UDP 数据 (2)在 UDP 连接列表中寻找接收到的数据包是否属于列表中的连接,若是则 goto udp_found;
如果不是则 goto drop;
udp_found: (1)接收到数据数设置 uip_flags = UIP_NEWDATA; 将 uip_sappdata ,uip_appdata 指向接收 到的 UDP 包的数据部分。 (2)调用 UIP_UDP_APPCALL();使应用程序处理接收到的数据; (3)继续向下执行 udp_send: (1)如果 uip_slen == 0 表明没有数据要发送,则直接 goto drop; (2)计算 UDP 数据包长度,填充 UDP、IP 帧头中的数据长度及相关选项; (3)根据要求计算校验和; (4)goto ip_send_nolen;发送 UDP 数据包;
case UIP_ESTABLISHED: (1)接收到远方主机的 FIN 请求:
① uip_flags |= UIP_CLOSE;关闭 TCP 连接 ②如果接收到的数据包中还包含有数据则 uip_flags |= UIP_NEWDATA; ③调用 UIP_APPCALL()处理刚关闭的连接和新接收到数据; ④发送 TCP_FIN +TCP_ACK,关闭连接; (2)如果接收到的数据状态为 UIP_NEWDATA | UIP_ACKDATA 则: ①调用 UIP_APPCALL();处理接收到的包; ② appsend: (1)如果(uip_flags & UIP_ABORT)终止连接则
reset: (1)接收到的是 RST 断开连接包,则直接丢包,返回; (2)设置 RST+ACK 标志,填充适当的 TCP 帧头; (3)goto tcp_send_noconn;发送 TCP 数据包;
found_listen: (1)从链接列表中找出一个空链接或剩余生存时间最短的连接; (2)将找到的链接列表根据接收到的 TCP 数据包进行初始化; (3)设置 TCP 状态为 UIP_SYN_RCVD; (4)向下执行,发送 ACK tcp_send_synack: (1)设置 ACK 标志 (2)向下执行 tcp_send_syn: (1)设置 SYN 标志 (2)填充 TCP 选项中最大报文段长度 MSS (3) goto tcp_send;
①tcpstateflags = UIP_CLOSED;将连接置为关闭状态 ②uip_flags = UIP_CLOSE;调用 UIP_APPCALL();通知应用程序连接已经断开;
case UIP_FIN_WAIT_1: (1)此时本机已经关闭连接等待对方关闭连接,如果接收到数据并不处理,仅仅将接收到数 据包数目加一; (2)如果接收到 FIN 请求:
①goto drop;本机只处理 UDP、TCP、ICMP 数据包,其它包都将丢弃
(8)运行到此处,表明接收到的是 ICMP 数据包,继续向下执行; ——————————————————————————————————————— icmp_input:
此处为 ICMP 数据包处理部分,比较简单不做详解。 此部分仅仅接收 ECHO 命令,若接收到别的命令,则将数据包丢弃。若接收到的是 ECHO 命令则返回包含 ECHO_REPLY 的 ICMP 数据包给远方主机,主要是用来响应 ping 命令。
case UIP_FIN_WAIT_1: case UIP_CLOSING:
case UIP_LAST_ACK: goto tcp_send_finack;重发 FIN+ACK 关闭连接 } else if(tcpstateflags) == UIP_ESTABLISHED) 处于稳定连接状态且上次发送的数据
接收到正确的 ACK,可以继续发送新数据 {
①uip_flags = UIP_POLL;询问应用程序是否有数据要发送 ②UIP_APPCALL();调用应用程序产生数据 ③goto appsend;发送数据 } } goto drop; } if(flag == UIP_UDP_TIMER) { 当前连接的本地端口不为 0 则 { ①uip_len = uip_slen = 0; ②uip_flags = UIP_POLL;询问应用程序是否有数据要发送 ③UIP_UDP_APPCALL();调用应用程序产生数据 ④goto udp_send; } 本地端口为 0,表明没有建立 DUP 连接,则 { goto drop; } }
case UIP_SYN_RCVD: goto tcp_send_synack;重新发送先前发送的 SYN+ACK
case UIP_SYN_SENT: goto tcp_send_syn;重发 SYN 请求连接
case UIP_ESTABLISHED: uip_flags = UIP_REXMIT; UIP_APPCALL(); 调用上层应用程序,通知重新生Βιβλιοθήκη Baidu数据重发 goto apprexmit;进入重发阶段
TCP 状态机 switch(tcpstateflags)
case UIP_SYN_RCVD: (1)检查 uip_flags==UIP_ACKDATA 即是否接收到对自己发送 SYN 的 ACK 确认,
若是则: ①cpstateflags = UIP_ESTABLISHED;/*进入 ESTABLISHED 状态*/