00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "src/common/shared.hpp"
00011 #include "src/memory/memset.hpp"
00012 #include "src/memory/align.hpp"
00013 #include "src/memory/heap.hpp"
00014 #include "src/net/icmp.hpp"
00015 #include "src/net/arp.hpp"
00016 #include "src/net/ip.hpp"
00017
00022 #define INTERVAL_BETWEEN_ICMP_ERRORS 200
00023 #define DEBUG_ICMP_CHECKSUM_ALERT 0
00024
00027 namespace Net {
00028 namespace ICMP {
00029
00031 volatile uint64 next_icmp_error=0;
00032
00033 void processDatagram(struct Net::netbuf *nb) {
00034 struct Net::IP::ip_header *iph = reinterpret_cast<struct Net::IP::ip_header*>(&nb->data[14]);
00035 struct icmp_header *icmph = reinterpret_cast<struct icmp_header*>(&nb->data[14+sizeof(uint32)*iph->hdr_len]);
00036 uint32 icmp_data_len = ntohs(iph->len) - iph->hdr_len*sizeof(uint32);
00037 if (count_checksum16_icmph(icmph, icmp_data_len) != icmph->checksum) {
00038 #if DEBUG_ICMP_CHECKSUM_ALERT
00039 println(*icmph);
00040 println(*iph);
00041 println(*nb);
00042 for (int i=0;i<ntohs(iph->len)-iph->hdr_len*sizeof(uint32);i++) prin("(", i,")", ((uint8*)icmph)[i], ":");
00043 println();
00044 println("icmp packet len: ", icmp_data_len, " checksum should be: ", count_checksum16_icmph(icmph, ntohs(iph->len) - iph->hdr_len*sizeof(uint32)));
00045 complain("icmp checksum erroneus, packet dropped");
00046 #endif
00047 } else {
00048 switch (icmph->type) {
00049 case 0x00:
00050 break;
00051 case 0x08:
00052 if (Arch::x86::RTC::up_time < next_icmp_error) break;
00053 else next_icmp_error = Arch::x86::RTC::up_time+INTERVAL_BETWEEN_ICMP_ERRORS;
00054 struct packet_t *p = pbuf_alloc(icmp_data_len+200);
00056 p->off=180;
00057 p->end=p->off + icmp_data_len - sizeof(struct icmp_header);
00058 memmove(&p->buf[p->off], icmph->dt, icmp_data_len);
00059 icmp_transmit(iph->source_ip, p, 0x00, 0x00, icmph->data );
00060 break;
00061 }
00062 }
00063
00064 }
00065
00066 uint16 count_checksum16_icmph(struct icmp_header *icmph, uint32 len) {
00067 assert(sizeof(struct icmp_header) == 8);
00068 uint16 v= icmph->checksum;
00069 icmph->checksum=0;
00070 uint16 ret= count_checksum16(reinterpret_cast<uint16*>(icmph), (len));
00071 icmph->checksum=v;
00072 return ret;
00073 }
00074
00075 void icmp_transmit(struct ip_address ip_addr, struct Net::packet_t *p, uint8 type, uint8 code, uint32 data) {
00076 testif(p != null);
00077 testif(p->off >= sizeof(struct icmp_header));
00078 p->off -= sizeof(struct icmp_header);
00079 struct icmp_header *icmph = reinterpret_cast<struct icmp_header*>(&p->buf[p->off]);
00080 icmph->type = type;
00081 icmph->code = code;
00082 icmph->data = data;
00083 icmph->checksum=count_checksum16_icmph(icmph, p->end-p->off);
00084
00085 Net::IP::ip_transmit(ip_addr, 0, 0x01, p);
00086 }
00087
00088 }
00089 }
00090
00091 void print(struct Net::ICMP::icmp_header icmph) {
00092 prin("(icmp-h: type=", icmph.type, " code=", icmph.code, " checksum=", Net::ntohs(icmph.checksum));
00093
00094
00095
00096
00097
00098
00099 prin(" dt=", icmph.data,")");
00100 }
00101
00102