📄 uip.c
字号:
/* Find an unused local port. */ again: ++lastport; if(lastport >= 32000) { lastport = 4096; } for(c = 0; c < UIP_UDP_CONNS; ++c) { if(uip_udp_conns[c].lport == htons(lastport)) { goto again; } } conn = 0; for(c = 0; c < UIP_UDP_CONNS; ++c) { if(uip_udp_conns[c].lport == 0) { conn = &uip_udp_conns[c]; break; } } if(conn == 0) { return 0; } conn->lport = HTONS(lastport); conn->rport = rport; if(ripaddr == NULL) { memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); } else { uip_ipaddr_copy(&conn->ripaddr, ripaddr); } conn->ttl = UIP_TTL; return conn;}#endif /* UIP_UDP *//*---------------------------------------------------------------------------*/voiduip_unlisten(u16_t port){ for(c = 0; c < UIP_LISTENPORTS; ++c) { if(uip_listenports[c] == port) { uip_listenports[c] = 0; return; } }}/*---------------------------------------------------------------------------*/voiduip_listen(u16_t port){ for(c = 0; c < UIP_LISTENPORTS; ++c) { if(uip_listenports[c] == 0) { uip_listenports[c] = port; return; } }}/*---------------------------------------------------------------------------*//* XXX: IP fragment reassembly: not well-tested. */#if UIP_REASSEMBLY && !UIP_CONF_IPV6#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};static u16_t uip_reasslen;static u8_t uip_reassflags;#define UIP_REASS_FLAG_LASTFRAG 0x01static u8_t uip_reasstmr;#define IP_MF 0x20static u8_tuip_reass(void){ u16_t offset, len; u16_t i; /* If ip_reasstmr is zero, no packet is present in the buffer, so we write the IP header of the fragment into the reassembly buffer. The timer is updated with the maximum age. */ if(uip_reasstmr == 0) { memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); uip_reasstmr = UIP_REASS_MAXAGE; uip_reassflags = 0; /* Clear the bitmap. */ memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); } /* Check if the incoming fragment matches the one currently present in the reasembly buffer. If so, we proceed with copying the fragment into the buffer. */ if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] && BUF->srcipaddr[1] == FBUF->srcipaddr[1] && BUF->destipaddr[0] == FBUF->destipaddr[0] && BUF->destipaddr[1] == FBUF->destipaddr[1] && BUF->ipid[0] == FBUF->ipid[0] && BUF->ipid[1] == FBUF->ipid[1]) { len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; /* If the offset or the offset + fragment length overflows the reassembly buffer, we discard the entire packet. */ if(offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE) { uip_reasstmr = 0; goto nullreturn; } /* Copy the fragment into the reassembly buffer, at the right offset. */ memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), len); /* Update the bitmap. */ if(offset / (8 * 8) == (offset + len) / (8 * 8)) { /* If the two endpoints are in the same byte, we only update that byte. */ uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7] & ~bitmap_bits[((offset + len) / 8 ) & 7]; } else { /* If the two endpoints are in different bytes, we update the bytes in the endpoints and fill the stuff inbetween with 0xff. */ uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7]; for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { uip_reassbitmap[i] = 0xff; } uip_reassbitmap[(offset + len) / (8 * 8)] |= ~bitmap_bits[((offset + len) / 8 ) & 7]; } /* If this fragment has the More Fragments flag set to zero, we know that this is the last fragment, so we can calculate the size of the entire packet. We also set the IP_REASS_FLAG_LASTFRAG flag to indicate that we have received the final fragment. */ if((BUF->ipoffset[0] & IP_MF) == 0) { uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; uip_reasslen = offset + len; } /* Finally, we check if we have a full packet in the buffer. We do this by checking if we have the last fragment and if all bits in the bitmap are set. */ if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { /* Check all bytes up to and including all but the last byte in the bitmap. */ for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { if(uip_reassbitmap[i] != 0xff) { goto nullreturn; } } /* Check the last byte in the bitmap. It should contain just the right amount of bits. */ if(uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { goto nullreturn; } /* If we have come this far, we have a full packet in the buffer, so we allocate a pbuf and copy the packet into it. We also reset the timer. */ uip_reasstmr = 0; memcpy(BUF, FBUF, uip_reasslen); /* Pretend to be a "normal" (i.e., not fragmented) IP packet from now on. */ BUF->ipoffset[0] = BUF->ipoffset[1] = 0; BUF->len[0] = uip_reasslen >> 8; BUF->len[1] = uip_reasslen & 0xff; BUF->ipchksum = 0; BUF->ipchksum = ~(uip_ipchksum()); return uip_reasslen; } } nullreturn: return 0;}#endif /* UIP_REASSEMBLY *//*---------------------------------------------------------------------------*/static voiduip_add_rcv_nxt(u16_t n){ uip_add32(uip_conn->rcv_nxt, n); uip_conn->rcv_nxt[0] = uip_acc32[0]; uip_conn->rcv_nxt[1] = uip_acc32[1]; uip_conn->rcv_nxt[2] = uip_acc32[2]; uip_conn->rcv_nxt[3] = uip_acc32[3];}/*---------------------------------------------------------------------------*/voiduip_process(u8_t flag){ register struct uip_conn *uip_connr = uip_conn;#if UIP_UDP if(flag == UIP_UDP_SEND_CONN) { 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; } } 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. */ 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; 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; #if UIP_ACTIVE_OPEN case UIP_SYN_SENT: /* In the SYN_SENT state, we retransmit out SYN. */ BUF->flags = 0; goto tcp_send_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; } } } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { /* 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) { 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; } }#endif /* This is where the input processing starts. */ UIP_STAT(++uip_stat.ip.recv); /* Start of IP input header processing code. */ #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; }#else /* UIP_CONF_IPV6 */ /* Check validity of the IP header. */ if(BUF->vhl != 0x45) { /* IP version and header length. */ UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.vhlerr); UIP_LOG("ip: invalid version or header length."); 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 */ /* 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 */ if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so, proceed with TCP input
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -