📄 uip.c
字号:
/* In all these states we should retransmit a FINACK. */
goto tcp_send_finack;
}
}
} else if((uip_conn->tcpstateflags & TS_MASK) == ESTABLISHED) {
/* If there was no need for a retransmission, we poll the
application for new data. */
uip_len = 0;
uip_flags = UIP_POLL;
UIP_APPCALL();
goto appsend;
}
}
goto drop;
}
/* This is where the input processing starts. */
UIP_STAT(++uip_stat.ip.recv);
/* 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:vhl");
goto drop;
}
/* Check the size of the packet. If the size reported to us in
uip_len doesn't match the size reported in the IP header, there
has been a transmission error and we drop the packet. */
#if UIP_BUFSIZE > 255
if(BUF->len[0] != (uip_len >> 8)) {
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.hblenerr);
UIP_LOG("ip:len");
/* IP length, high byte. */
goto drop;
}
if(BUF->len[1] != (uip_len & 0xff)) {
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.lblenerr);
UIP_LOG("ip:len");
/* IP length, low byte. */
goto drop;
}
#else
if(BUF->len[0] != 0) { /* IP length, high byte. */
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.hblenerr);
UIP_LOG("ip:len");
goto drop;
}
if(BUF->len[1] != uip_len) { /* IP length, low byte. */
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.lblenerr);
UIP_LOG("ip:len");
goto drop;
}
#endif /* UIP_BUFSIZE > 255 */
if(BUF->ipoffset[0] & 0x3f) { /* We don't allow IP fragments. */
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.fragerr);
UIP_LOG("ip:frag");
goto drop;
}
/* Check if the packet is destined for our IP address. */
if(BUF->destipaddr[0] != htons(((u16_t)UIP_IPADDR0 << 8) | UIP_IPADDR1)) {
UIP_STAT(++uip_stat.ip.drop);
UIP_LOG("ip:wrnip");
goto drop;
}
if(BUF->destipaddr[1] != htons(((u16_t)UIP_IPADDR2 << 8) | UIP_IPADDR3)) {
UIP_STAT(++uip_stat.ip.drop);
UIP_LOG("ip:wrnip");
goto drop;
}
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:ck");
goto drop;
}
if(BUF->proto == IP_PROTO_TCP) /* Check for TCP packet. If so, jump
to the tcp_input label. */
goto tcp_input;
if(BUF->proto != IP_PROTO_ICMP) { /* We only allow ICMP packets from
here. */
UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.protoerr);
UIP_LOG("ip:prot");
goto drop;
}
UIP_STAT(++uip_stat.icmp.recv);
/* 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) {
UIP_STAT(++uip_stat.icmp.drop);
UIP_STAT(++uip_stat.icmp.typeerr);
UIP_LOG("icmp:");
goto drop;
}
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. */
tmpport = BUF->destipaddr[0];
BUF->destipaddr[0] = BUF->srcipaddr[0];
BUF->srcipaddr[0] = tmpport;
tmpport = BUF->destipaddr[1];
BUF->destipaddr[1] = BUF->srcipaddr[1];
BUF->srcipaddr[1] = tmpport;
UIP_STAT(++uip_stat.icmp.sent);
goto send;
/* TCP input processing. */
tcp_input:
UIP_STAT(++uip_stat.tcp.recv);
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:csum");
goto drop;
}
/* Demultiplex this segment. */
/* First check any active connections. */
for(uip_conn = &uip_conns[0]; uip_conn < &uip_conns[UIP_CONNS]; ++uip_conn) {
if(uip_conn->tcpstateflags != CLOSED &&
BUF->srcipaddr[0] == uip_conn->ripaddr[0] &&
BUF->srcipaddr[1] == uip_conn->ripaddr[1] &&
BUF->destport == uip_conn->lport &&
BUF->srcport == uip_conn->rport)
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_SYN)
goto reset;
tmpport = BUF->destport;
/* Next, check listening connections. */
for(c = 0; c < UIP_LISTENPORTS && uip_listenports[c] != 0; ++c) {
if(tmpport == uip_listenports[c])
goto found_listen;
}
/* 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)
goto drop;
UIP_STAT(++uip_stat.tcp.rst);
BUF->flags = TCP_RST | TCP_ACK;
uip_len = 40;
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. */
tmpport = BUF->srcport;
BUF->srcport = BUF->destport;
BUF->destport = tmpport;
/* Swap IP addresses. */
tmpport = BUF->destipaddr[0];
BUF->destipaddr[0] = BUF->srcipaddr[0];
BUF->srcipaddr[0] = tmpport;
tmpport = BUF->destipaddr[1];
BUF->destipaddr[1] = BUF->srcipaddr[1];
BUF->srcipaddr[1] = tmpport;
/* And send out the RST packet! */
goto tcp_send_noconn;
/* 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. */
for(c = 0; c < UIP_CONNS; ++c) {
if(uip_conns[c].tcpstateflags == CLOSED)
goto found_unused_connection;
}
for(c = 0; c < UIP_CONNS; ++c) {
if(uip_conns[c].tcpstateflags == TIME_WAIT)
goto found_unused_connection;
}
/* 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:con");
goto drop;
/* This label will be jumped to if we have found an unused
connection that we can use. */
found_unused_connection:
uip_conn = &uip_conns[c];
/* Fill in the necessary fields for the new connection. */
uip_conn->timer = UIP_RTO;
uip_conn->nrtx = 0;
uip_conn->lport = BUF->destport;
uip_conn->rport = BUF->srcport;
uip_conn->ripaddr[0] = BUF->srcipaddr[0];
uip_conn->ripaddr[1] = BUF->srcipaddr[1];
uip_conn->tcpstateflags = SYN_RCVD | UIP_OUTSTANDING;
uip_conn->snd_nxt[0] = uip_conn->ack_nxt[0] = iss[0];
uip_conn->snd_nxt[1] = uip_conn->ack_nxt[1] = iss[1];
uip_conn->snd_nxt[2] = uip_conn->ack_nxt[2] = iss[2];
uip_conn->snd_nxt[3] = uip_conn->ack_nxt[3] = iss[3];
uip_add_ack_nxt(1);
/* rcv_nxt should be the seqno from the incoming packet + 1. */
uip_conn->rcv_nxt[3] = BUF->seqno[3];
uip_conn->rcv_nxt[2] = BUF->seqno[2];
uip_conn->rcv_nxt[1] = BUF->seqno[1];
uip_conn->rcv_nxt[0] = BUF->seqno[0];
uip_add_rcv_nxt(1);
/* Parse the TCP MSS option, if present. */
if((BUF->tcpoffset & 0xf0) > 0x50) {
for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
opt = uip_buf[40 + UIP_LLH_LEN + c];
if(opt == 0x00) {
/* End of options. */
break;
} else if(opt == 0x01) {
++c;
/* NOP option. */
} else if(opt == 0x02 &&
uip_buf[40 + UIP_LLH_LEN + c + 1] == 0x04) {
/* An MSS option with the right option length. */
tmpport = (uip_buf[40 + UIP_LLH_LEN + c + 2] << 8) |
uip_buf[40 + UIP_LLH_LEN + c + 3];
uip_conn->mss = tmpport > UIP_TCP_MSS? UIP_TCP_MSS: tmpport;
/* And we are done processing options. */
break;
} else {
/* All other options have a length field, so that we easily
can skip past them. */
c += uip_buf[40 + UIP_LLH_LEN + c + 1];
}
}
}
/* Our response will be a SYNACK. */
#if UIP_ACTIVE_OPEN
tcp_send_synack:
BUF->flags = TCP_ACK;
tcp_send_syn:
BUF->flags |= TCP_SYN;
#else /* UIP_ACTIVE_OPEN */
tcp_send_synack:
BUF->flags = TCP_SYN | TCP_ACK;
#endif /* UIP_ACTIVE_OPEN */
/* We send out the TCP Maximum Segment Size option with our
SYNACK. */
BUF->optdata[0] = 2;
BUF->optdata[1] = 4;
BUF->optdata[2] = (UIP_TCP_MSS) / 256;
BUF->optdata[3] = (UIP_TCP_MSS) & 255;
uip_len = 44;
BUF->tcpoffset = 6 << 4;
goto tcp_send;
/* This label will be jumped to if we found an active connection. */
found:
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) {
uip_conn->tcpstateflags = CLOSED;
UIP_LOG("tcp:r");
uip_flags = UIP_ABORT;
UIP_APPCALL();
goto drop;
}
/* All segments that are come thus far should have the ACK flag set,
otherwise we drop the packet. */
if(!(BUF->flags & TCP_ACK)) {
UIP_STAT(++uip_stat.tcp.drop);
UIP_STAT(++uip_stat.tcp.ackerr);
UIP_LOG("tcp:na");
goto drop;
}
/* Calculated the length of the data, if the application has sent
any data to us. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -