/* * iphelp.cpp - ip router * * Basilisk II (C) 1997-2001 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdeps.h" #include "cpu_emulation.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "tcp.h" #include "icmp.h" #include "udp.h" #include "iphelp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" void make_icmp_checksum( icmp_t *icmp, int len ) { icmp->checksum = 0; uint16 sz = (len-sizeof(ip_t))/2; uint16 *p = (uint16 *)( (uint8 *)icmp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; ichecksum = htons((uint16)sum32); } void make_tcp_checksum( tcp_t *tcp, int len ) { tcp->checksum = 0; int tcp_len = len - sizeof(ip_t); uint16 sz = tcp_len/2; uint16 *p = (uint16 *)( (uint8 *)tcp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; iip.src)); pseudo.src_hi = HIWORD(ntohl(tcp->ip.src)); pseudo.dest_lo = LOWORD(ntohl(tcp->ip.dest)); pseudo.dest_hi = HIWORD(ntohl(tcp->ip.dest)); pseudo.proto = (uint16)tcp->ip.proto; pseudo.msg_len = tcp->header_len >> 2; int datalen = len - sizeof(tcp_t); pseudo.msg_len += datalen; p = (uint16 *)&pseudo; for( int i=0; ichecksum = htons((uint16)sum32); } void make_ip4_checksum( ip_t *ip ) { ip->checksum = 0; uint16 sz = ip->header_len * 2; uint16 *p = (uint16 *)( (uint8 *)ip + sizeof(mac_t) ); uint32 sum32 = 0; for( int i=0; ichecksum = htons((uint16)sum32); } void make_udp_checksum( udp_t *udp ) { udp->checksum = 0; return; // UDP checksums are optional. /* uint16 sz = ntohs(udp->msg_len) / 2; uint16 *p = (uint16 *)( (uint8 *)udp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; iip.src)); pseudo.src_hi = HIWORD(ntohl(udp->ip.src)); pseudo.dest_lo = LOWORD(ntohl(udp->ip.dest)); pseudo.dest_hi = HIWORD(ntohl(udp->ip.dest)); pseudo.proto = (uint16)udp->ip.proto; pseudo.msg_len = ntohs(udp->msg_len); // ??? p = (uint16 *)&pseudo; for( i=0; ichecksum = htons((uint16)sum32); */ } void error_winsock_2_icmp( int err, ip_t *ip_err, int dlen_err ) { int type = -1, code = -1, msg_size = 0; switch( err ) { case WSAEHOSTUNREACH: case WSAETIMEDOUT: type = icmp_Destination_unreachable; code = 1; // Host unreachable msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; case WSAENETDOWN: case WSAENETUNREACH: type = icmp_Destination_unreachable; code = 0; // Network unreachable msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; case WSAETTLEXCEEDED: type = icmp_Time_exceeded; code = 0; // Transit TTL exceeded msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; } if(type >= 0 && macos_ip_address != 0) { D(bug("sending icmp error reply. type=%d, code=%d, msg_size=%d\r\n", type, code, msg_size)); int icmp_size = sizeof(icmp_t) + msg_size; icmp_t *icmp = (icmp_t *)malloc( icmp_size ); if(icmp) { mac_t *mac = (mac_t *)icmp; ip_t *ip = (ip_t *)icmp; memcpy( mac->dest, ether_addr, 6 ); memcpy( mac->src, router_mac_addr, 6 ); mac->type = htons(mac_type_ip4); ip->version = 4; ip->header_len = 5; ip->tos = 0; ip->total_len = htons(sizeof(icmp_t) - sizeof(mac_t) + msg_size); ip->ident = htons(next_ip_ident_number++); ip->flags_n_frag_offset = 0; ip->ttl = 128; ip->proto = ip_proto_icmp; ip->src = htonl(router_ip_address); ip->dest = htonl(macos_ip_address); make_ip4_checksum( ip ); icmp->type = type; icmp->code = code; // zero out the unused field memset( (char *)icmp + sizeof(icmp_t), 0, sizeof(uint32) ); // copy 64 bits of original message memcpy( (char *)icmp + sizeof(icmp_t) + sizeof(uint32), (char *)ip_err + sizeof(mac_t), msg_size ); make_icmp_checksum( icmp, icmp_size ); dump_bytes( (uint8 *)icmp, icmp_size ); enqueue_packet( (uint8 *)icmp, icmp_size ); free(icmp); } } }