uip1.0核心模块uip_process函数解读
轉載地址:https://www.amobbs.com/thread-5531817-1-1.html
?最近,利用uip搞了小東西,要想利用好uip, 最好徹底搞清楚其關鍵函數 uip_process.
當網卡接收到數據之后,均需要通過該函數來處理.
??下面是對uip 1.0中的uip_process函數解讀.
//要點: 網卡收到數據時,uip_process會遍歷uip_udp_conns數組,如果當前包的目的端口與
//本機端口不匹配,或者遠程端口與uip_udp_new中的端口不匹配,那么uip會直接丟棄
//這個包。
void uip_process(u8_t flag)
{
??u8_t temp[2];
??register struct uip_conn *uip_connr = uip_conn;
#if UIP_UDP
??if(flag == UIP_UDP_SEND_CONN) {? ? ? ???//若是則goto udp_send;不是則向下執行;
? ? goto udp_send;
??}
#endif /* UIP_UDP */
??
??uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
??/* Check if we were invoked because of a poll request for a
? ???particular connection. */
??if(flag == UIP_POLL_REQUEST) { // 如果處于穩定連接狀態且沒有數據在緩存中等待確認則:
? ? if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED &&
? ?? ? !uip_outstanding(uip_connr)) {
? ? ? ? uip_flags = UIP_POLL;
? ? ? ? UIP_APPCALL();
? ? ? ? goto appsend;
? ? }
? ? goto drop;
? ??
? ? /* Check if we were invoked because of the perodic timer fireing. */
??} else if(flag == UIP_TIMER) {
#if UIP_REASSEMBLY
? ? if(uip_reasstmr != 0) {
? ?? ?--uip_reasstmr;
? ? }
#endif /* UIP_REASSEMBLY */
? ? /* Increase the initial sequence number. */
? ? if(++iss[3] == 0) {
? ?? ?if(++iss[2] == 0) {
? ? ? ? if(++iss[1] == 0) {
? ? ? ?? ?++iss[0];
? ? ? ? }
? ?? ?}
? ? }
? ? /* Reset the length variables. */
? ? uip_len = 0;
? ? uip_slen = 0;
? ? /* Check if the connection is in a state in which we simply wait
? ?? ? for the connection to time out. If so, we increase the
? ?? ? connection's timer and remove the connection if it times
? ?? ? out. */
? ? if(uip_connr->tcpstateflags == UIP_TIME_WAIT ||
? ?? ? uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
? ?? ?++(uip_connr->timer);
? ?? ?if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
? ?//如果連接處于等待超時關閉狀態則增加超時計數器,如果到達超時期限則關閉當前連接
? ? ? ?? ?? ? uip_connr->tcpstateflags = UIP_CLOSED;
? ? ? ? ? ? ? ?? ?//uip_arp_close(uip_connr->ripaddr);
? ?? ?}
? ? } else if(uip_connr->tcpstateflags != UIP_CLOSED) {? ? ? ? //如果連接不處于關閉狀態
? ?? ?/* If the connection has outstanding data, we increase the
? ? ? ???connection's timer and see if it has reached the RTO value
? ? ? ???in which case we retransmit. */
//已經發送的數據包還未接收到對其的ACK,超時計數器減一且超時計數器值為0??
? ?? ?if(uip_outstanding(uip_connr)) {
? ? ? ? if(uip_connr->timer-- == 0) {
? ? ? ?? ?if(uip_connr->nrtx == UIP_MAXRTX ||
? ? ? ?? ?? ?((uip_connr->tcpstateflags == UIP_SYN_SENT ||
? ? ? ?? ?? ???uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
? ? ? ?? ?? ? uip_connr->nrtx == UIP_MAXSYNRTX)) {
? ? ? ?? ?//①如果到達所設定的重發次數則
? ? ? ?? ???uip_connr->tcpstateflags = UIP_CLOSED;//關閉當前連接
? ? ? ?? ???/* We call UIP_APPCALL() with uip_flags set to
? ? ? ?? ?? ???UIP_TIMEDOUT to inform the application that the
? ? ? ?? ?? ???connection has timed out. */
? ? ? ?? ???uip_flags = UIP_TIMEDOUT; //通知應用程序超時;
? ? ? ?? ???UIP_APPCALL();
? ? ? ?? ???/* We also send a reset packet to the remote host. */
? ? ? ?? ???BUF->flags = TCP_RST | TCP_ACK;? ? ? ?? ?//設置RST+ACK終止連接標志
? ? ? ?? ???goto tcp_send_nodata;
? ? ? ?? ?}
? ?//②沒有到達設定的重發次數則重傳數據:
? ? ? ?? ?/* Exponential backoff. */
? ? ? ?? ?uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???4:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???uip_connr->nrtx);? ? ? ? //重置重傳計數器
? ? ? ?? ?++(uip_connr->nrtx);
? ? ? ?? ?
? ? ? ?? ?/* Ok, so we need to retransmit. We do this differently
? ? ? ?? ?? ?depending on which state we are in. In ESTABLISHED, we
? ? ? ?? ?? ?call upon the application so that it may prepare the
? ? ? ?? ?? ?data for the retransmit. In SYN_RCVD, we resend the
? ? ? ?? ?? ?SYNACK that we sent earlier and in LAST_ACK we have to
? ? ? ?? ?? ?retransmit our FINACK. */
? ? ? ?? ?UIP_STAT(++uip_stat.tcp.rexmit);
? ? ? ?? ?switch(uip_connr->tcpstateflags & UIP_TS_MASK) {//根據連接處的不同狀態重發不同的數據包
? ? ? ?? ?case UIP_SYN_RCVD:
? ? ? ?? ???/* In the SYN_RCVD state, we should retransmit our
? ?? ?? ?? ?? ?SYNACK. */
? ? ? ?? ???goto tcp_send_synack; // 重新發送先前發送的SYN+ACK?
? ? ? ?? ???
#if UIP_ACTIVE_OPEN
? ? ? ?? ?case UIP_SYN_SENT:
? ? ? ?? ???/* In the SYN_SENT state, we retransmit out SYN. */
? ? ? ?? ???BUF->flags = 0;
? ? ? ?? ???goto tcp_send_syn;? ? ? ???//重發SYN請求連接
#endif /* UIP_ACTIVE_OPEN */
? ? ? ?? ???
? ? ? ?? ?case UIP_ESTABLISHED:
? ? ? ?? ???/* In the ESTABLISHED state, we call upon the application
? ?? ?? ?? ?? ?to do the actual retransmit after which we jump into
? ?? ?? ?? ?? ?the code for sending out the packet (the apprexmit
? ?? ?? ?? ?? ?label). */
? ? ? ?? ???uip_flags = UIP_REXMIT;
? ? ? ?? ???UIP_APPCALL();? ? ? ? //調用上層應用程序,通知重新生成數據重發
? ? ? ?? ???goto apprexmit;? ? ? ? //進入重發階段
? ? ? ?? ???
? ? ? ?? ?case UIP_FIN_WAIT_1:
? ? ? ?? ?case UIP_CLOSING:
? ? ? ?? ?case UIP_LAST_ACK:
? ? ? ?? ???/* In all these states we should retransmit a FINACK. */
? ? ? ?? ???goto tcp_send_finack;//重發FIN+ACK關閉連接?
? ? ? ?? ???
? ? ? ?? ?}
? ? ? ? }
? ? } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {??//處于穩定連接狀態且上次發送的數據?
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//接收到正確的ACK,可以繼續發送新數據?
? ? ? ? /* If there was no need for a retransmission, we poll the
? ?? ?? ???application for new data. */
? ? ? ? uip_flags = UIP_POLL; //詢問應用程序是否有數據要發送?
? ? ? ? UIP_APPCALL();//調用應用程序產生數據
? ? ? ? goto appsend;//發送數據
? ?? ?}
? ? }
? ? goto drop;
??}
#if UIP_UDP
??if(flag == UIP_UDP_TIMER) {
? ? if(uip_udp_conn->lport != 0) { //當前連接的本地端口不為0則
? ?? ?uip_conn = NULL;
? ?? ?uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
? ?? ?uip_len = uip_slen = 0;
? ?? ?uip_flags = UIP_POLL;? ? ? ???//詢問應用程序是否有數據要發送
? ?? ?UIP_UDP_APPCALL();//調用應用程序產生數據
? ?? ?goto udp_send;
? ? } else {
? ?? ?goto drop;//本地端口為0,表明沒有建立DUP連接,則
? ? }
??}
#endif
??/* This is where the input processing starts. */
??UIP_STAT(++uip_stat.ip.recv);
??/* Start of IP input header processing code. */
??//檢查IP幀頭中的IP版本及IP頭長度是否符合要
#if UIP_CONF_IPV6
??/* Check validity of the IP header. */
??if((BUF->vtc & 0xf0) != 0x60)??{ /* IP version and header length. */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.vhlerr);
? ? UIP_LOG("ipv6: invalid version.");
? ? goto drop; //不符合:goto drop;丟棄此包
??}
#else /* UIP_CONF_IPV6 */
??/* Check validity of the IP header. others 0x69,0x46 ? */
??if(BUF->vhl != 0x45)??{ /* IP version and header length. */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.vhlerr);
? ? ? ? temp[0]=??BUF->vhl;
? ? ? ? temp[1]='\0';
? ? ? ? UIP_LOG(temp);
? ? UIP_LOG("ip: invalid version or header length.");
? ? goto drop;//不符合:goto drop;丟棄此包
??}
#endif /* UIP_CONF_IPV6 */
??
??/* Check the size of the packet. If the size reported to us in
? ???uip_len is smaller the size reported in the IP header, we assume
? ???that the packet has been corrupted in transit. If the size of
? ???uip_len is larger than the size reported in the IP packet header,
? ???the packet has been padded and we set uip_len to the correct
? ???value.. */
??if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
? ? uip_len = (BUF->len[0] << 8) + BUF->len[1];
#if UIP_CONF_IPV6
? ? uip_len += 40; /* The length reported in the IPv6 header is the
? ? ? ? ? ? ? ?? ?? ? length of the payload that follows the
? ? ? ? ? ? ? ?? ?? ? header. However, uIP uses the uip_len variable
? ? ? ? ? ? ? ?? ?? ? for holding the size of the entire packet,
? ? ? ? ? ? ? ?? ?? ? including the IP header. For IPv4 this is not a
? ? ? ? ? ? ? ?? ?? ? problem as the length field in the IPv4 header
? ? ? ? ? ? ? ?? ?? ? contains the length of the entire packet. But
? ? ? ? ? ? ? ?? ?? ? for IPv6 we need to add the size of the IPv6
? ? ? ? ? ? ? ?? ?? ? header (40 bytes). */
#endif /* UIP_CONF_IPV6 */
??} else {
? ? UIP_LOG("ip: packet shorter than reported in IP header.");
? ? goto drop;
??}
#if !UIP_CONF_IPV6
??/* Check the fragment flag. */
??if((BUF->ipoffset[0] & 0x3f) != 0 ||
? ???BUF->ipoffset[1] != 0) {
#if UIP_REASSEMBLY
? ? uip_len = uip_reass();
? ? if(uip_len == 0) {
? ?? ?goto drop;
? ? }
#else /* UIP_REASSEMBLY */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.fragerr);
? ? UIP_LOG("ip: fragment dropped.");
? ? goto drop;
#endif /* UIP_REASSEMBLY */
??}
#endif /* UIP_CONF_IPV6 */
??if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) {
? ? /* If we are configured to use ping IP address configuration and
? ?? ? hasn't been assigned an IP address yet, we accept all ICMP
? ?? ? packets. */
#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
? ? if(BUF->proto == UIP_PROTO_ICMP) {
? ?? ?UIP_LOG("ip: possible ping config packet received.");
? ?? ?goto icmp_input;
? ? } else {
? ?? ?UIP_LOG("ip: packet dropped since no address assigned.");
? ?? ?goto drop;
? ? }
#endif /* UIP_PINGADDRCONF */
??} else {
? ? /* If IP broadcast support is configured, we check for a broadcast
? ?? ? UDP packet, which may be destined to us. */
#if UIP_BROADCAST
? ? DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum());
? ? if(BUF->proto == UIP_PROTO_UDP &&
? ?? ? uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr)
? ?? ? /*&&
? ? ? ???uip_ipchksum() == 0xffff*/) {
? ?? ?goto udp_input;
? ? }
#endif /* UIP_BROADCAST */
? ? //檢查目的IP地址是否為本機地址
? ? /* Check if the packet is destined for our IP address. */
#if !UIP_CONF_IPV6
? ? if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) {
? ?? ?UIP_STAT(++uip_stat.ip.drop);
? ?? ?goto drop;//不是,丟棄此包
? ? }
#else /* UIP_CONF_IPV6 */
? ? /* For IPv6, packet reception is a little trickier as we need to
? ?? ? make sure that we listen to certain multicast addresses (all
? ?? ? hosts multicast address, and the solicited-node multicast
? ?? ? address) as well. However, we will cheat here and accept all
? ?? ? multicast packets that are sent to the ff02::/16 addresses. */
? ? if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) &&
? ?? ? BUF->destipaddr[0] != HTONS(0xff02)) {
? ?? ?UIP_STAT(++uip_stat.ip.drop);
? ?? ?goto drop;//不是,丟棄此包
? ? }
#endif /* UIP_CONF_IPV6 */
??}
#if !UIP_CONF_IPV6
??if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ???checksum. */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.chkerr);
? ? UIP_LOG("ip: bad checksum.");
? ? goto drop;
??}
#endif /* UIP_CONF_IPV6 */
??//IP上層協議是否為TCP協議?
??if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ???proceed with TCP input
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ???processing. */
? ? goto tcp_input;? ? ? ? //進入TCP數據處理模塊
??}
#if UIP_UDP
??if(BUF->proto == UIP_PROTO_UDP) {? ? ? ?? ?//IP上層協議是否為UDP協議?
? ? goto udp_input;? ? ? ? //進入UDP數據處理模塊
??}
#endif /* UIP_UDP */
#if !UIP_CONF_IPV6
??/* ICMPv4 processing code follows. */? ? ? ??
??//不是TCP不是UDP也不是ICMP協議?
??if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? here. */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.protoerr);
? ? UIP_LOG("ip: neither tcp nor icmp.");
? ? goto drop;? ? ? ???//本機只處理UDP、TCP、ICMP數據包,其它包都將丟棄?
??}
#if UIP_PINGADDRCONF
icmp_input: //是ICMP數據包
#endif /* UIP_PINGADDRCONF */
??UIP_STAT(++uip_stat.icmp.recv);
??//ICMP數據包處理部分
??/* ICMP echo (i.e., ping) processing. This is simple, we only change
? ???the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
? ???checksum before we return the packet. */
??if(ICMPBUF->type != ICMP_ECHO) {? ? ? ? //僅僅接收ECHO命令
? ? UIP_STAT(++uip_stat.icmp.drop);
? ? UIP_STAT(++uip_stat.icmp.typeerr);
? ? UIP_LOG("icmp: not icmp echo.");
? ? goto drop;? ? ? ? //若接收到別的命令,則將數據包丟棄。
??}
??/* If we are configured to use ping IP address assignment, we use
? ???the destination IP address of this ping packet and assign it to
? ???ourself. */
#if UIP_PINGADDRCONF
??if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
? ? uip_hostaddr[0] = BUF->destipaddr[0];
? ? uip_hostaddr[1] = BUF->destipaddr[1];
??}
#endif /* UIP_PINGADDRCONF */
??//若接收到的是ECHO命令則返回包含ECHO_REPLY的ICMP數據包給遠方主機,主要是用來響應ping命令
??ICMPBUF->type = ICMP_ECHO_REPLY;
??if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
? ? ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
??} else {
? ? ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
??}
??/* Swap IP addresses. */
??uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
??uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
??UIP_STAT(++uip_stat.icmp.sent);
??goto send;
??/* End of IPv4 input header processing code. */
#else /* !UIP_CONF_IPV6 */
??/* This is IPv6 ICMPv6 processing code. */
??DEBUG_PRINTF("icmp6_input: length %d\n", uip_len);
??if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???here. */
? ? UIP_STAT(++uip_stat.ip.drop);
? ? UIP_STAT(++uip_stat.ip.protoerr);
? ? UIP_LOG("ip: neither tcp nor icmp6.");
? ? goto drop;
??}
??UIP_STAT(++uip_stat.icmp.recv);
??/* If we get a neighbor solicitation for our address we should send
? ???a neighbor advertisement message back. */
??if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) {
? ? if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) {
? ?? ?if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
? ? ? ? /* Save the sender's address in our neighbor list. */
? ? ? ? uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2]));
? ?? ?}
? ?? ?
? ?? ?/* We should now send a neighbor advertisement back to where the
? ? ? ???neighbor solicication came from. */
? ?? ?ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
? ?? ?ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */
? ?? ?
? ?? ?ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
? ?? ?
? ?? ?uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);
? ?? ?uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr);
? ?? ?ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
? ?? ?ICMPBUF->options[1] = 1;??/* Options length, 1 = 8 bytes. */
? ?? ?memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr));
? ?? ?ICMPBUF->icmpchksum = 0;
? ?? ?ICMPBUF->icmpchksum = ~uip_icmp6chksum();
? ?? ?goto send;
? ?? ?
? ? }
? ? goto drop;
??} else if(ICMPBUF->type == ICMP6_ECHO) {
? ? /* ICMP echo (i.e., ping) processing. This is simple, we only
? ?? ? change the ICMP type from ECHO to ECHO_REPLY and update the
? ?? ? ICMP checksum before we return the packet. */
??//返回包含ECHO_REPLY的ICMP數據包給遠方主機,主要是用來響應ping命令
? ? ICMPBUF->type = ICMP6_ECHO_REPLY;
? ??
? ? uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
? ? uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
? ? ICMPBUF->icmpchksum = 0;
? ? ICMPBUF->icmpchksum = ~uip_icmp6chksum();
? ??
? ? UIP_STAT(++uip_stat.icmp.sent);
? ? goto send;
??} else {
? ? DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type);
? ? UIP_STAT(++uip_stat.icmp.drop);
? ? UIP_STAT(++uip_stat.icmp.typeerr);
? ? UIP_LOG("icmp: unknown ICMP message.");
? ? goto drop;
??}
??/* End of IPv6 ICMP processing. */
??
#endif /* !UIP_CONF_IPV6 */
#if UIP_UDP
??/* UDP input processing. */
udp_input:
??/* UDP processing is really just a hack. We don't do anything to the
? ???UDP/IP headers, but let the UDP application do all the hard
? ???work. If the application sets uip_slen, it has a packet to
? ???send. */
#if UIP_UDP_CHECKSUMS
??uip_len = uip_len - UIP_IPUDPH_LEN;
??uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
??if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {? ? ? ?? ?//根據要求校驗UDP
? ? UIP_STAT(++uip_stat.udp.drop);
? ? UIP_STAT(++uip_stat.udp.chkerr);
? ? UIP_LOG("udp: bad checksum.");
? ? goto drop;
??}
#else /* UIP_UDP_CHECKSUMS */
??uip_len = uip_len - UIP_IPUDPH_LEN;
#endif /* UIP_UDP_CHECKSUMS */
//在UDP連接列表中尋找接收到的數據包是否屬于列表中的連接
??/* Demultiplex this UDP packet between the UDP "connections". */
??for(uip_udp_conn = &uip_udp_conns[0];
? ?? ?uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
? ?? ?++uip_udp_conn) {
? ? /* If the local UDP port is non-zero, the connection is considered
? ?? ? to be used. If so, the local port number is checked against the
? ?? ? destination port number in the received packet. If the two port
? ?? ? numbers match, the remote port number is checked if the
? ?? ? connection is bound to a remote port. Finally, if the
? ?? ? connection is bound to a remote IP address, the source IP
? ?? ? address of the packet is checked. */
? ? if(uip_udp_conn->lport != 0 &&
? ?? ? UDPBUF->destport == uip_udp_conn->lport &&
? ?? ? (uip_udp_conn->rport == 0 ||
? ?? ???UDPBUF->srcport == uip_udp_conn->rport) &&
? ?? ? (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||
? ? ? ? uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) ||
? ? ? ? uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
? ?? ?goto udp_found;
? ? }
??}
??UIP_LOG("udp: no matching connection found");
??goto drop;??//如果不是則
??
udp_found:
??uip_conn = NULL;
??uip_flags = UIP_NEWDATA;? ? ? ? //接收到數據
??uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; //指向接收到的UDP包的數據部分
??uip_slen = 0;
??UIP_UDP_APPCALL();//使應用程序處理接收到的數據
udp_send:
??if(uip_slen == 0) { //表明沒有數據要發送
? ? goto drop;
??}
??//計算UDP數據包長度,填充UDP、IP幀頭中的數據長度及相關選項
??uip_len = uip_slen + UIP_IPUDPH_LEN;
#if UIP_CONF_IPV6
??/* For IPv6, the IP length field does not include the IPv6 IP header
? ???length. */
??BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
??BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
#else /* UIP_CONF_IPV6 */
??BUF->len[0] = (uip_len >> 8);
??BUF->len[1] = (uip_len & 0xff);
#endif /* UIP_CONF_IPV6 */
??BUF->ttl = uip_udp_conn->ttl;
??BUF->proto = UIP_PROTO_UDP;
??UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
??UDPBUF->udpchksum = 0;
??BUF->srcport??= uip_udp_conn->lport;
??BUF->destport = uip_udp_conn->rport;
??uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
??uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr);
? ?
??uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
??//根據要求計算校驗和
#if UIP_UDP_CHECKSUMS
??/* Calculate UDP checksum. */
??UDPBUF->udpchksum = ~(uip_udpchksum());
??if(UDPBUF->udpchksum == 0) {
? ? UDPBUF->udpchksum = 0xffff;
??}
#endif /* UIP_UDP_CHECKSUMS */
??
??goto ip_send_nolen; //發送UDP數據包
#endif /* UIP_UDP */
??
??/* TCP input processing. */
tcp_input:
??UIP_STAT(++uip_stat.tcp.recv);
??/* Start of TCP input header processing code. */
??//檢查TCP校驗和,若正確向下繼續,若錯誤則丟棄此包直接返回
??if(uip_tcpchksum() != 0xffff) {? ?/* Compute and check the TCP
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ???checksum. */
? ? UIP_STAT(++uip_stat.tcp.drop);
? ? UIP_STAT(++uip_stat.tcp.chkerr);
? ? UIP_LOG("tcp: bad checksum.");
? ? goto drop;
??}
??//在TCP連接列表uip_conns中輪詢,檢查接收到的TCP數據包是否已經建立連接
??//(通過逐個比較源端口、目的端口和源IP是否與鏈接列表中的相同)
??/* Demultiplex this segment. */
??/* First check any active connections. */
??for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
? ?? ?++uip_connr) {
? ? if(uip_connr->tcpstateflags != UIP_CLOSED &&
? ?? ? BUF->destport == uip_connr->lport &&
? ?? ? BUF->srcport == uip_connr->rport &&
? ?? ? uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) {
? ?? ?goto found;//若找到
? ? }
??}
??/* If we didn't find and active connection that expected the packet,
? ???either this packet is an old duplicate, or this is a SYN packet
? ???destined for a connection in LISTEN. If the SYN flag isn't set,
? ???it is an old packet and we send a RST. */
??if((BUF->flags & TCP_CTL) != TCP_SYN) {??//沒有找到則檢查接收到的TCP數據包中是否含有SYN請求建立連接標志
? ? goto reset;? ? ? ???//若沒有則,發送RST+ACK斷開連接
??}
??
??tmp16 = BUF->destport;
??/* Next, check listening connections. */
??for(c = 0; c < UIP_LISTENPORTS; ++c) {
? ? if(tmp16 == uip_listenports[c])
? ?? ?goto found_listen;//若有則檢查uip_listenports監聽列表,若TCP數據包目的端口在監聽列表中則
??}
//若不在監聽列表中則向下執行,進入 reset;發送RST+ACK斷開連接?
??/* No matching connection found, so we send a RST packet. */
??UIP_STAT(++uip_stat.tcp.synrst);
reset:
??/* We do not send resets in response to resets. */
??if (BUF->flags & TCP_RST) {? ? ? ? //接收到的是RST斷開連接包,則直接丟包返回
? ? ? ? //uip_arp_close(BUF->srcipaddr);?
? ? ? ???//增加對TCP_RST的響應處理,發送TCP_ACK
? ? ? ???UIP_LOG("tcp-1: got reset, aborting connection.");
? ?/* uip_connr->tcpstateflags = UIP_CLOSED;
? ? UIP_LOG("tcp-1: got reset, aborting connection.");
? ? uip_flags = UIP_ABORT;
? ? UIP_APPCALL();
//? ? ? ? uip_arp_close(uip_connr->ripaddr);
//增加對TCP_RST的響應處理,發送TCP_ACK
? ? BUF->flags = TCP_ACK;? ? ? ??
? ? ? ? goto tcp_send_nodata;*/
? ? goto drop;
??}
??UIP_STAT(++uip_stat.tcp.rst);
??//設置RST+ACK標志,填充適當的TCP幀頭
??BUF->flags = TCP_RST | TCP_ACK;
??uip_len = UIP_IPTCPH_LEN;
??BUF->tcpoffset = 5 << 4;
??/* Flip the seqno and ackno fields in the TCP header. */
??c = BUF->seqno[3];
??BUF->seqno[3] = BUF->ackno[3];
??BUF->ackno[3] = c;
??
??c = BUF->seqno[2];
??BUF->seqno[2] = BUF->ackno[2];
??BUF->ackno[2] = c;
??
??c = BUF->seqno[1];
??BUF->seqno[1] = BUF->ackno[1];
??BUF->ackno[1] = c;
??
??c = BUF->seqno[0];
??BUF->seqno[0] = BUF->ackno[0];
??BUF->ackno[0] = c;
??/* We also have to increase the sequence number we are
? ???acknowledging. If the least significant byte overflowed, we need
? ???to propagate the carry to the other bytes as well. */
??if(++BUF->ackno[3] == 0) {
? ? if(++BUF->ackno[2] == 0) {
? ?? ?if(++BUF->ackno[1] == 0) {
? ? ? ? ++BUF->ackno[0];
? ?? ?}
? ? }
??}
??/* Swap port numbers. */
??tmp16 = BUF->srcport;
??BUF->srcport = BUF->destport;
??BUF->destport = tmp16;
??
??/* Swap IP addresses. */
??uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
??uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
??
??/* And send out the RST packet! */
??goto tcp_send_noconn;//發送TCP數據
??/* This label will be jumped to if we matched the incoming packet
? ???with a connection in LISTEN. In that case, we should create a new
? ???connection and send a SYNACK in return. */
found_listen:? ? ? ? //被動連接
??/* First we check if there are any connections avaliable. Unused
? ???connections are kept in the same table as used connections, but
? ???unused ones have the tcpstate set to CLOSED. Also, connections in
? ???TIME_WAIT are kept track of and we'll use the oldest one if no
? ???CLOSED connections are found. Thanks to Eddie C. Dost for a very
? ???nice algorithm for the TIME_WAIT search. */
??uip_connr = 0;
??for(c = 0; c < UIP_CONNS; ++c) {
? ? if(uip_conns[c].tcpstateflags == UIP_CLOSED) { //從鏈接列表中找出一個空鏈接或剩余生存時間最短的連接
? ?? ?uip_connr = &uip_conns[c];
? ?? ?break;
? ? }
? ? if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
? ?? ?if(uip_connr == 0 ||
? ? ? ???uip_conns[c].timer > uip_connr->timer) {
? ? ? ? uip_connr = &uip_conns[c];
? ?? ?}
? ? }
??}
??if(uip_connr == 0) {
? ? /* All connections are used already, we drop packet and hope that
? ?? ? the remote end will retransmit the packet at a time when we
? ?? ? have more spare connections. */
? ? UIP_STAT(++uip_stat.tcp.syndrop);
? ? UIP_LOG("tcp: found no unused connections.");
? ? goto drop;
??}
??uip_conn = uip_connr;? ? ? ? //將找到的鏈接列表根據接收到的TCP數據包進行初始化
??
??/* Fill in the necessary fields for the new connection. */
??uip_connr->rto = uip_connr->timer = UIP_RTO;
??uip_connr->sa = 0;
??uip_connr->sv = 4;
??uip_connr->nrtx = 0;
??uip_connr->lport = BUF->destport;
??uip_connr->rport = BUF->srcport;
??uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr);
??uip_connr->tcpstateflags = UIP_SYN_RCVD;//設置TCP狀態為UIP_SYN_RCVD
??uip_connr->snd_nxt[0] = iss[0];??// 第二次握手用的seqno賦值,該值是有暫定。
??uip_connr->snd_nxt[1] = iss[1];
??uip_connr->snd_nxt[2] = iss[2];
??uip_connr->snd_nxt[3] = iss[3];
??uip_connr->len = 1;
??/* rcv_nxt should be the seqno from the incoming packet + 1. */
??uip_connr->rcv_nxt[3] = BUF->seqno[3];? ?// 將對方第一次握手發送的seqno+1賦值給
??uip_connr->rcv_nxt[2] = BUF->seqno[2];? ?// 第二次握手用的ackno
??uip_connr->rcv_nxt[1] = BUF->seqno[1];
??uip_connr->rcv_nxt[0] = BUF->seqno[0];
??uip_add_rcv_nxt(1);
//分析TCP的最大段長度
??/* Parse the TCP MSS option, if present. */
??if((BUF->tcpoffset & 0xf0) > 0x50) {
? ? for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
? ?? ?opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
? ?? ?if(opt == TCP_OPT_END) {
? ? ? ? /* End of options. */
? ? ? ? break;
? ?? ?} else if(opt == TCP_OPT_NOOP) {
? ? ? ? ++c;
? ? ? ? /* NOP option. */
? ?? ?} else if(opt == TCP_OPT_MSS &&
? ? ? ? ? ? ? ? uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
? ? ? ? /* An MSS option with the right option length. */
? ? ? ? tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
? ? ? ?? ?(u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
? ? ? ? uip_connr->initialmss = uip_connr->mss =
? ? ? ?? ?tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
? ? ? ??
? ? ? ? /* And we are done processing options. */
? ? ? ? break;
? ?? ?} else {
? ? ? ? /* All other options have a length field, so that we easily
? ? ? ?? ? can skip past them. */
? ? ? ? if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
? ? ? ?? ?/* If the length field is zero, the options are malformed
? ? ? ?? ?? ?and we don't process them further. */
? ? ? ?? ?break;
? ? ? ? }
? ? ? ? c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
? ?? ?}
? ? }
??}
//發送ACK?
??/* Our response will be a SYNACK. */
#if UIP_ACTIVE_OPEN
tcp_send_synack:
??BUF->flags = TCP_ACK;//設置ACK標志
??
tcp_send_syn:
??BUF->flags |= TCP_SYN; //設置SYN標志
#else /* UIP_ACTIVE_OPEN */
tcp_send_synack:
??BUF->flags = TCP_SYN | TCP_ACK;
#endif /* UIP_ACTIVE_OPEN */
??//填充TCP選項中最大報文段長度MSS
??/* We send out the TCP Maximum Segment Size option with our
? ???SYNACK. */
??BUF->optdata[0] = TCP_OPT_MSS;
??BUF->optdata[1] = TCP_OPT_MSS_LEN;
??BUF->optdata[2] = (UIP_TCP_MSS) / 256;
??BUF->optdata[3] = (UIP_TCP_MSS) & 255;
??uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
??BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
??goto tcp_send;
??/* This label will be jumped to if we found an active connection. */
found:? ? ? ?? ?//主動鏈接部分
??uip_conn = uip_connr;
??uip_flags = 0;
??/* We do a very naive form of TCP reset processing; we just accept
? ???any RST and kill our connection. We should in fact check if the
? ???sequence number of this reset is wihtin our advertised window
? ???before we accept the reset. */
??if(BUF->flags & TCP_RST) {//若接收到的是RST數據包,則將本連接狀態置為UIP_CLOSED
? ? uip_connr->tcpstateflags = UIP_CLOSED;
? ? UIP_LOG("tcp: got reset, aborting connection.");
? ? uip_flags = UIP_ABORT;
? ? UIP_APPCALL();? ? ? ???//通知應用程序處理連接斷開請求。然后丟棄此包,直接返回
? ? goto drop;
??}
??/* Calculated the length of the data, if the application has sent
? ???any data to us. */
??c = (BUF->tcpoffset >> 4) << 2;
??/* uip_len will contain the length of the actual TCP data. This is
? ???calculated by subtracing the length of the TCP header (in
? ???c) and the length of the IP header (20 bytes). */
??uip_len = uip_len - c - UIP_IPH_LEN;
??/* First, check if the sequence number of the incoming packet is
? ???what we're expecting next. If not, we send out an ACK with the
? ???correct numbers in. */
??if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
? ?? ? ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
? ? if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
? ?? ? (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
? ? ? ? BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
? ? ? ? BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
? ? ? ? BUF->seqno[3] != uip_connr->rcv_nxt[3])) { //檢查接收到的數據包中的數據編號是否為自己等在等待的數據編號
? ?? ?goto tcp_send_ack;? ?//若不是則發送自己期望的數據編號的數據,即請求重傳
? ? }
??}
??//檢查接收到的數據包中是否包含ACK
??/* Next, check if the incoming segment acknowledges any outstanding
? ???data. If so, we update the sequence number, reset the length of
? ???the outstanding data, calculate RTT estimations, and reset the
? ???retransmission timer. */
??if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {? ?// 收到了ACK幀,同時有待確認的數據
? ?// uip_connr->len 用于記錄本次發送的字節數
? ?// 在第三次握手中uip_connr->len = 1
? ? uip_add32(uip_connr->snd_nxt, uip_connr->len);// 計算下一次發送的第一個字節的序列號
? ? ? ???
? ? if(BUF->ackno[0] == uip_acc32[0] &&
? ?? ? BUF->ackno[1] == uip_acc32[1] &&
? ?? ? BUF->ackno[2] == uip_acc32[2] &&
? ?? ? BUF->ackno[3] == uip_acc32[3]) {
? ?? ?/* Update sequence number. */
? ?? ?uip_connr->snd_nxt[0] = uip_acc32[0];? ? ? ?? ?//更新發送數據序列的編號,使之可以發送后續數據
? ?? ?uip_connr->snd_nxt[1] = uip_acc32[1];
? ?? ?uip_connr->snd_nxt[2] = uip_acc32[2];
? ?? ?uip_connr->snd_nxt[3] = uip_acc32[3];
? ? ? ??
? ? ? ? // 計算RTT時間,重新設置RTT時間
? ?? ?/* Do RTT estimation, unless we have done retransmissions. */
? ?? ?if(uip_connr->nrtx == 0) {
? ? ? ? signed char m;
? ? ? ? m = uip_connr->rto - uip_connr->timer;
? ? ? ? /* This is taken directly from VJs original code in his paper */
? ? ? ? m = m - (uip_connr->sa >> 3);
? ? ? ? uip_connr->sa += m;
? ? ? ? if(m < 0) {
? ? ? ?? ?m = -m;
? ? ? ? }
? ? ? ? m = m - (uip_connr->sv >> 2);
? ? ? ? uip_connr->sv += m;
? ? ? ? uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
? ?? ?}
? ?? ?/* Set the acknowledged flag. */
? ?? ?uip_flags = UIP_ACKDATA;//表明接收到ACK
? ?? ?/* Reset the retransmission timer. */
? ?? ?uip_connr->timer = uip_connr->rto;
? ?? ?/* Reset length of outstanding data. */
? ?? ?uip_connr->len = 0; //表明等待ACK的數據長度為0,即可以發送其它數據?
? ? }
? ? ? ? else
? ? ? ? {
??? ?? ???//當MCU作為TCP服務器時,如果ackno 與 uip_acc32
? ?? ?? ? //不一致時,會引起無法重新連接或發送數據, 當時等待發起連接端情動TCP_RST之后,允許重新連接
? ?? ?? ?//需要在用戶應用里如何處理? 或這里增加如何處理?
? ? ? ?? ? UIP_LOG("tcp: snd_nxt ,ackno reset ??? .");
? ? ? ? }?
??}
//檢查TCP狀態機制
??/* Do different things depending on in what state the connection is. */
??switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
? ? /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
? ? ? ? implemented, since we force the application to close when the
? ? ? ? peer sends a FIN (hence the application goes directly from
? ? ? ? ESTABLISHED to LAST_ACK). */
??case UIP_SYN_RCVD: //是否接收到對自己發送SYN的ACK確認
? ? /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
? ?? ? we are waiting for an ACK that acknowledges the data we sent
? ?? ? out the last time. Therefore, we want to have the UIP_ACKDATA
? ?? ? flag set. If so, we enter the ESTABLISHED state. */
? ? if(uip_flags & UIP_ACKDATA) {
? ?? ?uip_connr->tcpstateflags = UIP_ESTABLISHED; //若是,進入ESTABLISHED狀態
? ?? ?uip_flags = UIP_CONNECTED; //連接成功
? ?? ?uip_connr->len = 0;
? ?? ?if(uip_len > 0) {? ? ? ???//檢查數據包長度是否包含數據部分
? ?? ???uip_flags |= UIP_NEWDATA; //是
? ?? ???uip_add_rcv_nxt(uip_len);
? ?? ?}
? ?? ?uip_slen = 0;
? ?? ?UIP_APPCALL(); //處理剛建立的連接和新接收到數據
? ?? ?goto appsend;
? ? }
? ? goto drop;//若不是則丟包返回;
#if UIP_ACTIVE_OPEN
??case UIP_SYN_SENT:
? ? /* In SYN_SENT, we wait for a SYNACK that is sent in response to
? ?? ? our SYN. The rcv_nxt is set to sequence number in the SYNACK
? ?? ? plus one, and we send an ACK. We move into the ESTABLISHED
? ?? ? state. */
? ? if((uip_flags & UIP_ACKDATA) &&
? ?? ? (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {? ? ? ? //如果接收到ACK且為SYN+ACK
? ?? ?/* Parse the TCP MSS option, if present. */
? ?? ?if((BUF->tcpoffset & 0xf0) > 0x50) { //檢查TCP擴展選項,如果有擴展選項從中取出MSS信息
? ? ? ? for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
? ? ? ?? ?opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
? ? ? ?? ?if(opt == TCP_OPT_END) {
? ? ? ?? ???/* End of options. */
? ? ? ?? ???break;
? ? ? ?? ?} else if(opt == TCP_OPT_NOOP) {
? ? ? ?? ???++c;
? ? ? ?? ???/* NOP option. */
? ? ? ?? ?} else if(opt == TCP_OPT_MSS &&
? ? ? ? ? ? ? ?? ???uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
? ? ? ?? ???/* An MSS option with the right option length. */
? ? ? ?? ???tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
? ? ? ?? ?? ? uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
? ? ? ?? ???uip_connr->initialmss =
? ? ? ?? ?? ? uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
? ? ? ?? ???/* And we are done processing options. */
? ? ? ?? ???break;
? ? ? ?? ?} else {
? ? ? ?? ???/* All other options have a length field, so that we easily
? ? ? ?? ?? ???can skip past them. */
? ? ? ?? ???if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
? ? ? ?? ?? ? /* If the length field is zero, the options are malformed
? ? ? ? ? ? ? ???and we don't process them further. */
? ? ? ?? ?? ? break;
? ? ? ?? ???}
? ? ? ?? ???c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
? ? ? ?? ?}
? ? ? ? }
? ?? ?}
? ?? ?uip_connr->tcpstateflags = UIP_ESTABLISHED; //進入ESTABLISHED狀態
? ?? ?//設置接收編號
? ? ? ?? ?uip_connr->rcv_nxt[0] = BUF->seqno[0];// 用于第三次握手的ackno,將收到的
? ?? ?uip_connr->rcv_nxt[1] = BUF->seqno[1]; // 第二次握手中的seqno+1賦值給第三
? ?? ?uip_connr->rcv_nxt[2] = BUF->seqno[2]; // 次握手中的ackno
? ?? ?uip_connr->rcv_nxt[3] = BUF->seqno[3];
? ?? ?uip_add_rcv_nxt(1);? ?// uip_connr->rcv_nxt[3] = uip_connr->rcv_nxt[3]+1
? ?? ?uip_flags = UIP_CONNECTED | UIP_NEWDATA; //設置接收編號
? ?? ?uip_connr->len = 0;
? ?? ?uip_len = 0;
? ?? ?uip_slen = 0;
? ?? ?UIP_APPCALL();//處理剛建立的連接和新接收到數據
? ?? ?goto appsend;
? ? }
? ? ? ? //沒有接收到ACK且為SYN+ACK則
? ? /* Inform the application that the connection failed */
? ? uip_flags = UIP_ABORT;//終止連接
? ? UIP_APPCALL();
? ? /* The connection is closed after we send the RST */
? ? uip_conn->tcpstateflags = UIP_CLOSED; //關閉TCP連接
? ? ? ? //uip_arp_close(uip_connr->ripaddr);
? ? goto reset;
#endif /* UIP_ACTIVE_OPEN */
? ??
??case UIP_ESTABLISHED:
? ? /* In the ESTABLISHED state, we call upon the application to feed
? ? data into the uip_buf. If the UIP_ACKDATA flag is set, the
? ? application should put new data into the buffer, otherwise we are
? ? retransmitting an old segment, and the application should put that
? ? data into the buffer.
? ? If the incoming packet is a FIN, we should close the connection on
? ? this side as well, and we send out a FIN and enter the LAST_ACK
? ? state. We require that there is no outstanding data; otherwise the
? ? sequence numbers will be screwed up. */
? ? ? ? //接收到遠方主機的FIN請求
? ? if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
? ?? ?if(uip_outstanding(uip_connr)) {
? ? ? ? goto drop;
? ?? ?}
//計算ackno:
? ?? ?uip_add_rcv_nxt(1 + uip_len);? ? ? ? //uip_connr->rcv_nxt+1+uip_len,其中uip_len是接收到的數據長度。
? ?? ?uip_flags |= UIP_CLOSE;? ? ? ? //關閉TCP連接
? ?? ?if(uip_len > 0) {
? ? ? ? uip_flags |= UIP_NEWDATA;//如果接收到的數據包中還包含有數據
? ?? ?}
? ?? ?UIP_APPCALL();
? ?? ?uip_connr->len = 1;
? ?? ?uip_connr->tcpstateflags = UIP_LAST_ACK;
? ?? ?uip_connr->nrtx = 0;
? ? tcp_send_finack:
? ?? ?BUF->flags = TCP_FIN | TCP_ACK;//發送TCP_FIN +TCP_ACK,關閉連接
? ?? ?goto tcp_send_nodata;
? ? }
? ? /* Check the URG flag. If this is set, the segment carries urgent
? ?? ? data that we must pass to the application. */
? ? if((BUF->flags & TCP_URG) != 0) {
#if UIP_URGDATA > 0
? ?? ?uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
? ?? ?if(uip_urglen > uip_len) {
? ? ? ? /* There is more urgent data in the next segment to come. */
? ? ? ? uip_urglen = uip_len;
? ?? ?}
? ?? ?uip_add_rcv_nxt(uip_urglen);
? ?? ?uip_len -= uip_urglen;
? ?? ?uip_urgdata = uip_appdata;
? ?? ?uip_appdata += uip_urglen;
? ? } else {
? ?? ?uip_urglen = 0;
#else /* UIP_URGDATA > 0 */
? ?? ?uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]);
? ?? ?uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
#endif /* UIP_URGDATA > 0 */
? ? }
? ? /* If uip_len > 0 we have TCP data in the packet, and we flag this
? ?? ? by setting the UIP_NEWDATA flag and update the sequence number
? ?? ? we acknowledge. If the application has stopped the dataflow
? ?? ? using uip_stop(), we must not accept any data packets from the
? ?? ? remote host. */
? ? if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
? ?? ?uip_flags |= UIP_NEWDATA;
? ?? ?uip_add_rcv_nxt(uip_len);
? ? }
? ? /* Check if the available buffer space advertised by the other end
? ?? ? is smaller than the initial MSS for this connection. If so, we
? ?? ? set the current MSS to the window size to ensure that the
? ?? ? application does not send more data than the other end can
? ?? ? handle.
? ?? ? If the remote host advertises a zero window, we set the MSS to
? ?? ? the initial MSS so that the application will send an entire MSS
? ?? ? of data. This data will not be acknowledged by the receiver,
? ?? ? and the application will retransmit it. This is called the
? ?? ? "persistent timer" and uses the retransmission mechanim.
? ? */
? ? tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
? ? if(tmp16 > uip_connr->initialmss ||
? ?? ? tmp16 == 0) {
? ?? ?tmp16 = uip_connr->initialmss;
? ? }
? ? uip_connr->mss = tmp16;
? ? /* If this packet constitutes an ACK for outstanding data (flagged
? ?? ? by the UIP_ACKDATA flag, we should call the application since it
? ?? ? might want to send more data. If the incoming packet had data
? ?? ? from the peer (as flagged by the UIP_NEWDATA flag), the
? ?? ? application must also be notified.
? ?? ? When the application is called, the global variable uip_len
? ?? ? contains the length of the incoming data. The application can
? ?? ? access the incoming data through the global pointer
? ?? ? uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
? ?? ? bytes into the uip_buf array.
? ?? ? If the application wishes to send any data, this data should be
? ?? ? put into the uip_appdata and the length of the data should be
? ?? ? put into uip_len. If the application don't have any data to
? ?? ? send, uip_len must be set to 0. */
? ? if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {//如果接收到的數據狀態
? ?? ?uip_slen = 0;
? ?? ?UIP_APPCALL(); //處理接收到的包
? ? appsend:
? ?? ?
? ?? ?if(uip_flags & UIP_ABORT) { //如果是終止連接
? ? ? ? uip_slen = 0;
? ? ? ? uip_connr->tcpstateflags = UIP_CLOSED;//終止連接
? ? ? ? BUF->flags = TCP_RST | TCP_ACK;? ? ? ? //發送RST+ACK關閉連接
? ? ? ? goto tcp_send_nodata;
? ?? ?}
? ?? ?if(uip_flags & UIP_CLOSE) { //如果是正常關閉連接
? ? ? ? uip_slen = 0;
? ? ? ? uip_connr->len = 1;
? ? ? ? uip_connr->tcpstateflags = UIP_FIN_WAIT_1; //進入等待關閉狀態
? ? ? ? uip_connr->nrtx = 0;
? ? ? ? BUF->flags = TCP_FIN | TCP_ACK;//發送FIN+ACK告知對方關閉連接
? ? ? ? goto tcp_send_nodata;
? ?? ?}
? ?? ?/* If uip_slen > 0, the application has data to be sent. */
? ?? ?if(uip_slen > 0) {??//如果有數據要發送則設置發送數據的長度
? ? ? ? /* If the connection has acknowledged data, the contents of
? ? ? ?? ? the ->len variable should be discarded. */
? ? ? ? if((uip_flags & UIP_ACKDATA) != 0) {
? ? ? ?? ?uip_connr->len = 0;
? ? ? ? }
? ? ? ? /* If the ->len variable is non-zero the connection has
? ? ? ?? ? already data in transit and cannot send anymore right
? ? ? ?? ? now. */
? ? ? ? if(uip_connr->len == 0) {
? ? ? ?? ?/* The application cannot send more than what is allowed by
? ? ? ?? ?? ?the mss (the minumum of the MSS and the available
? ? ? ?? ?? ?window). */
? ? ? ?? ?if(uip_slen > uip_connr->mss) {
? ? ? ?? ???uip_slen = uip_connr->mss;
? ? ? ?? ?}
? ? ? ?? ?/* Remember how much data we send out now so that we know
? ? ? ?? ?? ?when everything has been acknowledged. */
? ? ? ?? ?uip_connr->len = uip_slen;
? ? ? ? } else {
? ? ? ?? ?/* If the application already had unacknowledged data, we
? ? ? ?? ?? ?make sure that the application does not send (i.e.,
? ? ? ?? ?? ?retransmit) out more than it previously sent out. */
? ? ? ?? ?uip_slen = uip_connr->len;
? ? ? ? }
? ?? ?}
? ?? ?uip_connr->nrtx = 0;
? ? apprexmit:
? ?? ?uip_appdata = uip_sappdata;
? ?? ?
? ?? ?/* If the application has data to be sent, or if the incoming
? ?? ?? ?packet had new data in it, we must send out a packet. */
? ?? ?if(uip_slen > 0 && uip_connr->len > 0) {? ? ? ? //發送PSH_ACK數據包;
? ? ? ? /* Add the length of the IP and TCP headers. */
? ? ? ? uip_len = uip_connr->len + UIP_TCPIP_HLEN;
? ? ? ? /* We always set the ACK flag in response packets. */
? ? ? ? BUF->flags = TCP_ACK | TCP_PSH;
? ? ? ? /* Send the packet. */
? ? ? ? goto tcp_send_noopts;
? ?? ?}
? ?? ?/* If there is no data to send, just send out a pure ACK if
? ? ? ???there is newdata. */
? ?? ?if(uip_flags & UIP_NEWDATA) {//僅僅是發送ACK
? ? ? ? uip_len = UIP_TCPIP_HLEN;
? ? ? ? BUF->flags = TCP_ACK; //沒有數據要發送則發送對接收到數據的ACK
? ? ? ? goto tcp_send_noopts;
? ?? ?}
? ? }
? ? goto drop;
??case UIP_LAST_ACK:
? ? /* We can close this connection if the peer has acknowledged our
? ?? ? FIN. This is indicated by the UIP_ACKDATA flag. */
? ? if(uip_flags & UIP_ACKDATA) { //接收到對本機發送的FIN的ACK確認
? ?? ?uip_connr->tcpstateflags = UIP_CLOSED; //將連接置為關閉狀態
? ?? ?uip_flags = UIP_CLOSE;
? ?? ?UIP_APPCALL();? ? ? ? //通知應用程序連接已經斷開
? ? }
? ? break;
? ??
??case UIP_FIN_WAIT_1:
? ? /* The application has closed the connection, but the remote host
? ?? ? hasn't closed its end yet. Thus we do nothing but wait for a
? ?? ? FIN from the other side. */
? ? if(uip_len > 0) { //此時本機已經關閉連接等待對方關閉連接,如果接收到數據并不處理,僅僅將接收到數據包數目加一
? ?? ?uip_add_rcv_nxt(uip_len);
? ? }
? ? if(BUF->flags & TCP_FIN) { //如果接收到FIN請求
? ?? ?if(uip_flags & UIP_ACKDATA) {? ? ? ? //接收到對本機發送FIN的確認則將連接狀態置為
? ? ? ? uip_connr->tcpstateflags = UIP_TIME_WAIT;
? ? ? ? uip_connr->timer = 0;
? ? ? ? uip_connr->len = 0;
? ?? ?} else {
? ? ? ? uip_connr->tcpstateflags = UIP_CLOSING;? ? ? ? //將連接狀態置為
? ?? ?}
? ?? ?uip_add_rcv_nxt(1);
? ?? ?uip_flags = UIP_CLOSE;//通知應用程序有一方已經關閉連接
? ?? ?UIP_APPCALL();
? ?? ?goto tcp_send_ack;
? ? } else if(uip_flags & UIP_ACKDATA) { //僅僅接收到ACK則設置連接狀態標志
? ?? ?uip_connr->tcpstateflags = UIP_FIN_WAIT_2; // 進入等待對方關閉階段
? ?? ?uip_connr->len = 0;
? ?? ?goto drop;
? ? }
? ? if(uip_len > 0) { //表明接收到數據包
? ?? ?goto tcp_send_ack; //發送對接收到數據的確認ACK
? ? }
? ? goto drop;
? ?? ?
??case UIP_FIN_WAIT_2:
? ? if(uip_len > 0) { //此時本機已經關閉連接等待對方關閉連接,如果接收到數據并不處理,僅僅將接收到數據包數目加一
? ?? ?uip_add_rcv_nxt(uip_len);
? ? }
? ? if(BUF->flags & TCP_FIN) {//如果接收到對方發送的FIN請求
? ?? ?uip_connr->tcpstateflags = UIP_TIME_WAIT;//進入超時關閉狀態
? ?? ?uip_connr->timer = 0;
? ?? ?uip_add_rcv_nxt(1);
? ?? ?uip_flags = UIP_CLOSE;
? ?? ?UIP_APPCALL();//通知應用程序有一方已經關閉連接?
? ?? ?goto tcp_send_ack;
? ? }
? ? if(uip_len > 0) { //表明接收到數據包
? ?? ?goto tcp_send_ack;//發送對接收到數據的確認ACK
? ? }
? ? goto drop;
??case UIP_TIME_WAIT:
? ? goto tcp_send_ack;
? ??
??case UIP_CLOSING:
? ? if(uip_flags & UIP_ACKDATA) { //接收到對FIN的ACK
? ?? ?uip_connr->tcpstateflags = UIP_TIME_WAIT;? ? ? ? //連接進入超時等待狀態
? ?? ?uip_connr->timer = 0;
? ? }
??}
??goto drop;
??
??/* We jump here when we are ready to send the packet, and just want
? ???to set the appropriate TCP sequence numbers in the TCP header. */
tcp_send_ack:
??BUF->flags = TCP_ACK;//設置ACK標志
tcp_send_nodata:
??uip_len = UIP_IPTCPH_LEN;? ? ? ? //將長度設為幀頭長度,不包含數據
tcp_send_noopts:
??BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;? ? ? ???//將選項長度設為0
tcp_send:? ? ? ? //發送自己期望的數據編號的數據,即請求重發送自己期望的數據編號的數據,即請求重傳
??/* We're done with the input processing. We are now ready to send a
? ???reply. Our job is to fill in all the fields of the TCP and IP
? ???headers before calculating the checksum and finally send the
? ???packet. */
//寫入序號值, must do !!!?
//填充TCP幀頭確認編號和發送編號,IP地址和端口號
??BUF->ackno[0] = uip_connr->rcv_nxt[0];
??BUF->ackno[1] = uip_connr->rcv_nxt[1];
??BUF->ackno[2] = uip_connr->rcv_nxt[2];
??BUF->ackno[3] = uip_connr->rcv_nxt[3];
??
??BUF->seqno[0] = uip_connr->snd_nxt[0];
??BUF->seqno[1] = uip_connr->snd_nxt[1];
??BUF->seqno[2] = uip_connr->snd_nxt[2];
??BUF->seqno[3] = uip_connr->snd_nxt[3];
??BUF->proto = UIP_PROTO_TCP;
??
??BUF->srcport??= uip_connr->lport;
??BUF->destport = uip_connr->rport;
??uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
??uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr);
??if(uip_connr->tcpstateflags & UIP_STOPPED) { //要求暫停發送數據則將接收窗口設為0;禁止對方往自己發送數據
? ? /* If the connection has issued uip_stop(), we advertise a zero
? ?? ? window so that the remote host will stop sending data. */
? ? BUF->wnd[0] = BUF->wnd[1] = 0;
??} else {
? ? BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
? ? BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
??}
tcp_send_noconn:
??BUF->ttl = UIP_TTL; //設置TCP包生存時間,傳送的數據的長度
#if UIP_CONF_IPV6
??/* For IPv6, the IP length field does not include the IPv6 IP header
? ???length. */
??BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
??BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
#else /* UIP_CONF_IPV6 */
??BUF->len[0] = (uip_len >> 8);
??BUF->len[1] = (uip_len & 0xff);
#endif /* UIP_CONF_IPV6 */
??BUF->urgp[0] = BUF->urgp[1] = 0;
??
??/* Calculate TCP checksum. */
??BUF->tcpchksum = 0;
??BUF->tcpchksum = ~(uip_tcpchksum()); //)計算TCP校驗和
??
ip_send_nolen:
? ?//設置IP幀頭中的各個選項
#if UIP_CONF_IPV6
??BUF->vtc = 0x60;
??BUF->tcflow = 0x00;
??BUF->flow = 0x00;
#else /* UIP_CONF_IPV6 */
??BUF->vhl = 0x45;
??BUF->tos = 0;
??BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
??++ipid;
??BUF->ipid[0] = ipid >> 8;
??BUF->ipid[1] = ipid & 0xff;
??/* Calculate IP checksum. */
??BUF->ipchksum = 0;
??BUF->ipchksum = ~(uip_ipchksum()); //計算IP校驗和
//??DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum());
#endif /* UIP_CONF_IPV6 */
??
??UIP_STAT(++uip_stat.tcp.sent);
send:
// DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len,
//? ? ? ?? ?? ???(BUF->len[0] << 8) | BUF->len[1]);
? ?//將發送的數據包計數器加一
??UIP_STAT(++uip_stat.ip.sent);
??/* Return and let the caller do the actual transmission. */
??uip_flags = 0;
??return;
drop:
??uip_len = 0;
??uip_flags = 0;
??return;
}
?
/*---------------------------------------------------------------------------*
總結
以上是生活随笔為你收集整理的uip1.0核心模块uip_process函数解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java文件压缩加密
- 下一篇: Html5+Css实战前端小米官网左侧导