void icmps_rx(TCPIPS* tcpips, IO *io, IP* src) { ICMP_HEADER* icmp = io_data(io); //drop broken ICMP without control, because ICMP is control protocol itself if (io->data_size < sizeof(ICMP_HEADER)) { ips_release_io(tcpips, io); return; } if (ip_checksum(io_data(io), io->data_size)) { ips_release_io(tcpips, io); return; } switch (icmp->type) { case ICMP_CMD_ECHO_REPLY: icmps_rx_echo_reply(tcpips, io, src); break; #if (ICMP_ECHO) case ICMP_CMD_ECHO: icmps_rx_echo(tcpips, io, src); break; #endif case ICMP_CMD_DESTINATION_UNREACHABLE: icmps_rx_destination_unreachable(tcpips, io); break; case ICMP_CMD_TIME_EXCEEDED: icmps_rx_time_exceeded(tcpips, io); break; case ICMP_CMD_PARAMETER_PROBLEM: icmps_rx_parameter_problem(tcpips, io); break; default: #if (ICMP_DEBUG) printf("ICMP: unhandled type %d from ", icmp->type); ip_print(src); printf("\n"); #endif ips_release_io(tcpips, io); break; } }
static void icmps_rx_error(TCPIPS* tcpips, IO* io, ICMP_ERROR code) { //hide ICMP header for protocol-depending processing io->data_offset += sizeof(ICMP_HEADER); io->data_size -= sizeof(ICMP_HEADER); icmps_rx_error_process(tcpips, io, code); //restore ICMP header and release io->data_offset -= sizeof(ICMP_HEADER); io->data_size += sizeof(ICMP_HEADER); ips_release_io(tcpips, io); }
static inline void icmps_rx_parameter_problem(TCPIPS* tcpips, IO* io) { ICMP_HEADER_PARAM* icmp = io_data(io); //useless if no original header provided if (io->data_size < sizeof(ICMP_HEADER_PARAM) + sizeof(IP_HEADER) + 8) { ips_release_io(tcpips, io); return; } #if (ICMP_DEBUG) printf("ICMP: Parameter problem (%d) ", icmp->param); #endif icmps_rx_error(tcpips, io, icmp->code + ICMP_ERROR_PARAMETER); }
static inline void icmps_rx_time_exceeded(TCPIPS* tcpips, IO* io) { ICMP_HEADER* icmp = io_data(io); //useless if no original header provided if (io->data_size < sizeof(ICMP_HEADER) + sizeof(IP_HEADER) + 8) { ips_release_io(tcpips, io); return; } #if (ICMP_DEBUG) printf("ICMP: Time exceeded in transit (%d) ", icmp->code); #endif icmps_rx_error(tcpips, io, icmp->code + ICMP_ERROR_TTL_EXCEED); }
static inline void icmps_rx_destination_unreachable(TCPIPS* tcpips, IO* io) { ICMP_HEADER* icmp = io_data(io); //useless if no original header provided if (io->data_size < sizeof(ICMP_HEADER) + sizeof(IP_HEADER) + 8) { ips_release_io(tcpips, io); return; } #if (ICMP_DEBUG) printf("ICMP: Destination unreachable(%d) ", icmp->code); #endif icmps_rx_error(tcpips, io, icmp->code); }
static inline void icmps_rx_echo_reply(TCPIPS* tcpips, IO* io, IP* src) { ICMP_HEADER_ID_SEQ* icmp = io_data(io); #if (ICMP_DEBUG) printf("ICMP: ECHO REPLY from "); ip_print(src); printf("\n"); #endif //compare src, sequence, id and data. Maybe asynchronous response from failed request if ((tcpips->icmps.echo_ip.u32.ip != src->u32.ip) || (tcpips->icmps.id != be2short(icmp->id_be)) || (tcpips->icmps.seq != be2short(icmp->seq_be))) { ips_release_io(tcpips, io); return; } icmps_echo_complete(tcpips, (memcmp(((uint8_t*)io_data(io)) + sizeof(ICMP_HEADER), __ICMP_DATA_MAGIC, ICMP_DATA_MAGIC_SIZE)) ? ERROR_CRC : ERROR_OK); }
void udps_rx(TCPIPS* tcpips, IO* io, IP* src) { HANDLE handle; UDP_HEADER* hdr; UDP_HANDLE* uh; uint16_t src_port, dst_port; #if(UDP_BROADCAST) const IP* dst; dst = (const IP*)io_data(io) - 1; if (io->data_size < sizeof(UDP_HEADER) || udp_checksum(io_data(io), io->data_size, src, dst)) #else if (io->data_size < sizeof(UDP_HEADER) || udp_checksum(io_data(io), io->data_size, src, &tcpips->ips.ip)) #endif { ips_release_io(tcpips, io); return; } hdr = io_data(io); src_port = be2short(hdr->src_port_be); dst_port = be2short(hdr->dst_port_be); #if (UDP_DEBUG_FLOW) printf("UDP: "); ip_print(src); printf(":%d -> ", src_port); ip_print(&tcpips->ips.ip); printf(":%d, %d byte(s)\n", dst_port, io->data_size - sizeof(UDP_HEADER)); #endif //UDP_DEBUG_FLOW #if(DHCPS) if((dst_port == DHCP_SERVER_PORT)||(src_port == DHCP_CLIENT_PORT)) { io_hide(io, sizeof(UDP_HEADER)); if(dhcps_rx(tcpips,io,src)) udps_replay(tcpips,io,&__BROADCAST); else ips_release_io(tcpips, io); return; } #endif #if(DNSS) if((dst_port == DNS_PORT)&&(dst->u32.ip == tcpips->ips.ip.u32.ip)) { io_hide(io, sizeof(UDP_HEADER)); if(dnss_rx(tcpips,io,src)) udps_replay(tcpips,io,src); else ips_release_io(tcpips, io); return; } #endif //search in listeners handle = udps_find(tcpips, dst_port); if (handle != INVALID_HANDLE) { uh = so_get(&tcpips->udps.handles, handle); //listener or connected if (uh->remote_port == 0 || (uh->remote_port == src_port && uh->remote_addr.u32.ip == src->u32.ip)) udps_send_user(tcpips, src, io, handle); else handle = INVALID_HANDLE; } #if(UDP_BROADCAST) if ((handle == INVALID_HANDLE) && (dst->u32.ip != BROADCAST)) #else if (handle == INVALID_HANDLE) #endif { #if (UDP_DEBUG) printf("UDP: no connection, datagramm dropped\n"); #endif //UDP_DEBUG #if (ICMP) icmps_tx_error(tcpips, io, ICMP_ERROR_PORT, 0); #endif //ICMP } ips_release_io(tcpips, io); }