import lib::util { Util } import os::os { OS } import os::time { Time } struct IcmpRequest { host: u64 identifier: u64 sequence_number: u64 response_type_pointer: u64 } enum TcpSessionState: i64 { Idle = 0 Established = 1 Closed = 2 Connecting = 4 } struct TcpSession { local_mac: [u8] remote_mac: [u8] local_address: [u8] remote_address: [u8] local_port: u16 remote_port: u16 local_sequence_number: u32 acknowledgement_number: u32 timestamp_last_echo_reply: u32 timestamp_last_jiffies: i64 timestamp_origin: i64 last_window_size: u16 last_tx_sequence_number: u32 last_tx_was_acked: bool tx_chunk_counter: i64 state: TcpSessionState pending_data_to_transmit: [u8] received_data: [u8] received_frames: [[u8]] is_bound_socket: bool socket: u64 } enum TcpBindError: u64 { BadRequest = 1 SocketIsAlreadyBound = 2 } class TCPIP { public ipv4_address: [u8] public ipv4_netmask: [u8] public ipv4_network: [u8] public ipv4_gateway: [u8] public dns_server_address: [u8] public dns_server_port: u16 public mss_size: u16 public tx_queue: [[u8]] public ttl: u8 public arp_cache: [String:[u8]] public bound_sockets: [u16:u64] public dns_cache: [String:[u8]] public tcp_sessions: [TcpSession] public pending_dns_lookups: [u16:u64] public pending_dns_cached_entries: [u16:String] public pending_icmp_requests: [u16:u64] public timestamp_last_arp_request: i64 public rx_bytes: u64 public rx_frames: u64 public tx_bytes: u64 public tx_frames: u64 fn calculate_header_checksum(this, anon mut packet: [u8], offset: i64, count: i64) -> u16 { mut sum: i64 = 0 for i in 0..count { if (i & 1) == 1 { sum += packet[offset + i] as! i64 } else { sum += (packet[offset + i] as! i64 * 256) } } mut calculated_checksum: u16 = 0 let overflowable_checksum: i64 = (sum & 0xffff) + (sum >> 16) if overflowable_checksum < 65536 { calculated_checksum = ~((sum & 0xffff) as! u16 + (sum >> 16) as! u16) } else { calculated_checksum = ~(unchecked_add ((sum & 0xffff) as! u16, (sum >> 16) as! u16)) - 1 } return calculated_checksum } fn push_ethernet_header(this, mut packet: [u8], destination_mac: [u8], source_mac: [u8], ethertype: u16) throws { for i in 0..6 { packet.push(destination_mac[i]) } for i in 0..6 { packet.push(source_mac[i]) } Util::push_u16_to_u8_array(packet, ethertype) } fn push_arp_packet(this, mut packet: [u8], opcode: u16, sender_mac: [u8], sender_ipv4: [u8], target_mac: [u8], target_ipv4: [u8]) throws { let hardware_protocol_header_data: [u8] = [0x00, 0x01, 0x08, 0x00, 0x06, 0x04] for i in 0..6 { packet.push(hardware_protocol_header_data[i]) } Util::push_u16_to_u8_array(packet, opcode) for i in 0..6 { packet.push(sender_mac[i]) } for i in 0..4 { packet.push(sender_ipv4[i]) } for i in 0..6 { packet.push(target_mac[i]) } for i in 0..4 { packet.push(target_ipv4[i]) } } fn push_ipv4_header(this, mut packet: [u8], total_length: u16, flags: u8, protocol: u8, source_address: [u8], destination_address: [u8]) throws { packet.push(0x45u8) // version & header length packet.push(0x00u8) // differentiated services field Util::push_u16_to_u8_array(packet, total_length) // total length of entire packet let identification: u64 = OS::random() & 0xffff Util::push_u16_to_u8_array(packet, identification as! u16) packet.push(flags) packet.push(0x00u8) // fragment size (unused) packet.push(.ttl) // time-to-live packet.push(protocol) // protocol number Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder for i in 0..4 { packet.push(source_address[i]) } for i in 0..4 { packet.push(destination_address[i]) } let checksum = .calculate_header_checksum(packet, offset: 14, count: 20) packet[24] = (checksum >> 8) as! u8 packet[25] = (checksum & 0xff) as! u8 } fn push_udp_header(this, mut packet: [u8], source_port: u16, destination_port: u16, length: i64) throws { Util::push_u16_to_u8_array(packet, source_port) Util::push_u16_to_u8_array(packet, destination_port) Util::push_u16_to_u8_array(packet, length as! u16) Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder } fn send_arp_reply(mut this, anon mac_address: [u8], anon sender_mac_address: [u8], anon sender_ipv4_address: [u8]) throws { mut packet: [u8] = [] .push_ethernet_header(packet, destination_mac: sender_mac_address, source_mac: mac_address, ethertype: 0x0806) .push_arp_packet( packet opcode: 0x0002 sender_mac: mac_address sender_ipv4: .ipv4_address target_mac: sender_mac_address target_ipv4: sender_ipv4_address ) .tx_queue.push(packet) } public fn send_arp_request(mut this, anon mac_address: [u8], anon target_ipv4_address: [u8]) throws { if .timestamp_last_arp_request > 0 and (.timestamp_last_arp_request + 5000) > Time::jiffies() { return } mut packet: [u8] = [] .push_ethernet_header(packet, destination_mac: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], source_mac: mac_address, ethertype: 0x0806) .push_arp_packet( packet opcode: 0x0001 sender_mac: mac_address sender_ipv4: .ipv4_address target_mac: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] target_ipv4: target_ipv4_address ) .tx_queue.push(packet) .timestamp_last_arp_request = Time::jiffies() } fn insert_arp_cache_entry(mut this, ipv4_address: [u8], mac_address: [u8]) throws { .arp_cache[Util::get_hexadecimal_string_from_ipv4_u8_array(ipv4_address)] = mac_address } public fn process_arp_packet(mut this, anon mac_address: [u8], anon frame: [u8]) throws { let arp_packet = frame[14..] let hardware_type = Util::get_u16_from_u8_arrayslice(arp_packet, 0) let protocol_type = Util::get_u16_from_u8_arrayslice(arp_packet, 2) let hardware_size = arp_packet[4] let protocol_size = arp_packet[5] let opcode = Util::get_u16_from_u8_arrayslice(arp_packet, 6) let sender_mac_address: [u8] = [arp_packet[8], arp_packet[9], arp_packet[10], arp_packet[11], arp_packet[12], arp_packet[13]] let sender_ipv4_address: [u8] = [arp_packet[14], arp_packet[15], arp_packet[16], arp_packet[17]] let target_mac_address: [u8] = [arp_packet[18], arp_packet[19], arp_packet[20], arp_packet[21], arp_packet[22], arp_packet[23]] let target_ipv4_address: [u8] = [arp_packet[24], arp_packet[25], arp_packet[26], arp_packet[27]] // If any of these mismatch, the packet is invalid if hardware_type != 0x0001 or protocol_type != 0x0800 or hardware_size != 6 or protocol_size != 4 { return } // Add the sender to ARP cache .insert_arp_cache_entry(ipv4_address: sender_ipv4_address, mac_address: sender_mac_address) //print("Updated ARP cache entry for {}: ", sender_ipv4_address) //for i in 0..6 { // print("{:0>2x}", sender_mac_address[i]) // if (i < 5) { // print(":") // } //} //println(" ") match opcode { 1 => { // ARP request, check if our ipv4 address matches for i in 0..4 { if .ipv4_address[i] != target_ipv4_address[i] { // doesn't match, break break } } // matches, send ARP reply .send_arp_reply(mac_address, sender_mac_address, sender_ipv4_address) } else => { // unsupported opcode, ignore } } } public fn send_dns_query(mut this, anon mac_address: [u8], anon query: String, anon pointer_to_u32: u64) throws { mut cached_result: u32 = 0 if .dns_cache.contains(query) { cached_result += (.dns_cache[query][0] as! u32 * (256 * 256 * 256) as! u32) cached_result += (.dns_cache[query][1] as! u32 * (256 * 256) as! u32) cached_result += (.dns_cache[query][2] as! u32 * 256 as! u32) cached_result += .dns_cache[query][3] as! u32 unsafe { cpp { "u32 *r = (u32*)pointer_to_u32; r[0] = cached_result;" } } return } mut packet: [u8] = [] mut dns_packet: [u8] = [] let transaction_id: u64 = OS::random() & 0xffff Util::push_u16_to_u8_array(dns_packet, transaction_id as! u16) .pending_dns_lookups.set(transaction_id as! u16, pointer_to_u32) .pending_dns_cached_entries.set(transaction_id as! u16, query) let dns_header_data: [u8] = [0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] dns_packet.push_values(&dns_header_data) let segments = query.split(c'.') for segment in segments { dns_packet.push(segment.length() as! u8) //println("segment_length: {} bytes", segment.length()) unsafe { cpp { "const char *raw_string = segment.characters(); for (int i = 0; i < segment.length(); i++) dns_packet.push(raw_string[i]);" } } } dns_packet.push(0x00u8) let dns_footer_data: [u8] = [0x00, 0x01, 0x00, 0x01] dns_packet.push_values(&dns_footer_data) let source_port: u16 = (OS::random() & 0xffff) as! u16 let destination_port: u16 = .dns_server_port let destination_mac = .arp_cache[Util::get_hexadecimal_string_from_ipv4_u8_array(.ipv4_gateway)] .push_ethernet_header(packet, destination_mac, source_mac: mac_address, ethertype: 0x0800) .push_ipv4_header(packet, total_length: 28 + dns_packet.size() as! u16, flags: 0x00, protocol: 0x11, source_address: .ipv4_address, destination_address: .dns_server_address) .push_udp_header(packet, source_port, destination_port, length: 8 + dns_packet.size() as! i64) packet.push_values(&dns_packet) // Calculate UDP checksum mut checksum_packet: [u8] = [] // Source and destination IP for i in 26..34 { checksum_packet.push(packet[i]) } // Protocol checksum_packet.push(0x00u8) checksum_packet.push(0x11u8) // UDP Packet length let udp_packet_length: u16 = 8 + dns_packet.size() as! u16 Util::push_u16_to_u8_array(checksum_packet, udp_packet_length) // Source Port Util::push_u16_to_u8_array(checksum_packet, source_port) // Destination port Util::push_u16_to_u8_array(checksum_packet, destination_port) // UDP Packet length (again) Util::push_u16_to_u8_array(checksum_packet, udp_packet_length) // Data checksum_packet.push_values(&dns_packet) let checksum = .calculate_header_checksum(checksum_packet, offset: 0, count: checksum_packet.size() as! i64) packet[40] = (checksum >> 8) as! u8 packet[41] = (checksum & 0xff) as! u8 .tx_queue.push(packet) } public fn netinfo_process_client_request(mut this, anon mac_address: [u8]) throws { unsafe { cpp { "u64 *request = (u64*)0x300030; if (*request) { int i = 0; u64 *r = (u64*)*request; for (i = 0; i < 6; i++) { r[0] = (r[0] << 8) | mac_address[i]; if (i < 4) { r[1] = (r[1] << 8) | this->ipv4_address[i]; r[2] = (r[2] << 8) | this->ipv4_netmask[i]; r[3] = (r[3] << 8) | this->ipv4_network[i]; r[4] = (r[4] << 8) | this->ipv4_gateway[i]; r[5] = (r[5] << 8) | this->dns_server_address[i]; } } r[6] = this->dns_server_port; r[7] = this->rx_bytes; r[8] = this->rx_frames; r[9] = this->tx_bytes; r[10] = this->tx_frames; u32 *p = (u32*)r[11]; p[0] = 1; // pointer_to_u32 *request = 0; }" } } } public fn icmp_process_client_request(mut this, anon mac_address: [u8]) throws { mut did_receive_request = false mut destination_mac: [u8] = [] mut addr: u32 = 0 mut iden: u64 = 0 mut seq: u64 = 0 mut pointer_to_u32: u64 = 0 unsafe { cpp { "u64 *ls_request = (u64*)0x300020; if (*ls_request) { u64 *ls_r = (u64*)*ls_request; addr = ls_r[0]; }" } } // FIXME: This will crash if we 1) Ping a host on the local subnet that does not exist, then 2) subsequently ping the gateway. if (addr > 0) { mut remote_address_hex_string = Util::get_hexadecimal_string_from_ipv4_u8_array(.ipv4_gateway) if addr != Util::get_address_u32_from_ipv4_u8_array(.ipv4_gateway) { if .is_local_ipv4_address(Util::get_ipv4_u8_array_from_address_u32(addr)) { remote_address_hex_string = Util::get_hexadecimal_string_from_ipv4_u8_array(Util::get_ipv4_u8_array_from_address_u32(addr)) if not .arp_cache.contains(remote_address_hex_string) { // send arp request //println("send arp request for: {}", remote_address_hex_string) .send_arp_request(mac_address, Util::get_ipv4_u8_array_from_address_u32(addr)) return } } } destination_mac = .arp_cache[remote_address_hex_string] } else { return } unsafe { cpp { "u64 *request = (u64*)0x300020; if (*request) { did_receive_request = true; u64 *r = (u64*)*request; addr = r[0]; iden = r[1]; seq = r[2]; pointer_to_u32 = r[3]; *request = 0; }" } } if (did_receive_request) { .send_icmp_request(mac_address, destination_mac, addr, iden, seq, pointer_to_u32) did_receive_request = false } } public fn dns_process_client_request(mut this, anon mac_address: [u8]) throws { mut did_receive_request = false mut request_is_ipv4_address = true mut s = StringBuilder::create() mut pointer_to_u32: u64 = 0 unsafe { cpp { "u64 *request = (u64*)0x300010; if (*request) { did_receive_request = true; u64 *r = (u64*)*request; char const *chars = (char const*)r[0]; s.append_c_string(chars); for (int i = 0; i < s.to_string().length(); i++) if ((chars[i] < '0' || chars[i] > '9') && chars[i] != '.') request_is_ipv4_address = false; delete(chars); pointer_to_u32 = r[1]; *request = 0; }" } } if (did_receive_request) { if (request_is_ipv4_address) { let octets = s.to_string().split(c'.') mut u32_address: u32 = 0 u32_address += octets[3].to_number().value() u32_address += octets[2].to_number().value() << 8 u32_address += octets[1].to_number().value() << 16 u32_address += octets[0].to_number().value() << 24 unsafe { cpp { "u32 *r = (u32*)pointer_to_u32; r[0] = u32_address;" } } } else { .send_dns_query(mac_address, s.to_string(), pointer_to_u32) } did_receive_request = false } } fn send_icmp_request(mut this, anon mac_address: [u8], anon destination_mac: [u8], anon addr: u32, anon iden: u64, anon seq: u64, anon pointer_to_u32: u64) throws { mut packet: [u8] = [] mut destination_address: [u8] = [] Util::push_u32_to_u8_array(destination_address, addr) .pending_icmp_requests.set(iden as! u16, pointer_to_u32) let total_length: u16 = 84 .push_ethernet_header(packet, destination_mac, source_mac: mac_address, ethertype: 0x0800) .push_ipv4_header(packet, total_length, flags: 0x40, protocol: 0x01, source_address: .ipv4_address, destination_address) packet.push(0x08u8) // type for i in 0..3 { packet.push(0x00u8) // code, checksum placeholder } Util::push_u16_to_u8_array(packet, iden as! u16) Util::push_u16_to_u8_array(packet, seq as! u16) for i in 0..8 { packet.push(0x00u8) // FIXME: timestamp } mut ch: u8 = 0x20 for i in 0..48 { packet.push(ch) // data ch++ } let checksum = .calculate_header_checksum(packet, offset: 34, count: packet.size() as! i64 - 34) packet[36] = (checksum >> 8) as! u8 packet[37] = (checksum & 0xff) as! u8 .tx_queue.push(packet) } fn process_icmp_reply(mut this, anon frame: [u8]) throws { let iden = Util::get_u16_from_u8_array(frame, 38) let ttl: u16 = frame[22] as! u16 let payload_size: u16 = Util::get_u16_from_u8_array(frame, 16) - 20 mut result: u32 = 0 result = (payload_size as! u32) << 16 result += ttl as! u32 mut pointer_to_u32: u64 = 0 if .pending_icmp_requests.contains(iden) { pointer_to_u32 = .pending_icmp_requests[iden] } if pointer_to_u32 > 0 { unsafe { cpp { "u32 *r = (u32*)pointer_to_u32; r[0] = result;" } } } } fn send_icmp_reply(mut this, anon mac_address: [u8], anon frame: [u8]) throws { mut packet: [u8] = [] let ipv4_packet = frame[14..] let icmp_packet = frame[34..] mut destination_mac: [u8] = [] for octet in frame[6..12] { destination_mac.push(octet) } mut destination_address: [u8] = [] for octet in ipv4_packet[12..16] { destination_address.push(octet) } .push_ethernet_header(packet, destination_mac, source_mac: mac_address, ethertype: 0x0800) .push_ipv4_header(packet, total_length: frame.size() as! u16 - 14, flags: 0x40, protocol: 0x01, source_address: .ipv4_address, destination_address) for i in 0..4 { packet.push(0x00u8) // type, code, checksum placeholder } for i in 4..8 { packet.push(icmp_packet[i]) // identifier & sequence number } for i in 8..icmp_packet.size() { packet.push(icmp_packet[i]) // data } let checksum = .calculate_header_checksum(packet, offset: 34, count: packet.size() as! i64 - 34) packet[36] = (checksum >> 8) as! u8 packet[37] = (checksum & 0xff) as! u8 .tx_queue.push(packet) } public fn process_icmp_packet(mut this, anon mac_address: [u8], anon frame: [u8]) throws { let icmp_packet = frame[34..] let type = icmp_packet[0] let code = icmp_packet[1] let checksum: u16 = Util::get_u16_from_u8_arrayslice(icmp_packet, 2) let identifier: u16 = Util::get_u16_from_u8_arrayslice(icmp_packet, 4) let sequence_number: u16 = Util::get_u16_from_u8_arrayslice(icmp_packet, 6) match type { 0 => { // ICMP reply .process_icmp_reply(frame) } 8 => { // ICMP request, send ICMP reply .send_icmp_reply(mac_address, frame) } else => { // unsupported } } } fn tcp_is_fin(this, flags: u16) -> bool { if (flags & 1) == 1 { return true } return false } fn tcp_is_syn(this, flags: u16) -> bool { if (flags & 2) == 2 { return true } return false } fn tcp_is_reset(this, flags: u16) -> bool { if (flags & 4) == 4 { return true } return false } fn tcp_is_push(this, flags: u16) -> bool { if (flags & 8) == 8 { return true } return false } fn tcp_is_ack(this, flags: u16) -> bool { if (flags & 16) == 16 { return true } return false } fn tcp_is_urgent(this, flags: u16) -> bool { if (flags & 32) == 32 { return true } return false } fn tcp_syn_packet(mut this, anon mut session: TcpSession) throws { mut packet: [u8] = [] let header_length: u16 = 40 let flags: u16 = 0xa002 // SYN mut ipv4_total_length: u16 = 0 ipv4_total_length += 20; // IPv4 ipv4_total_length += header_length as! u16 // TCP .push_ethernet_header(packet, destination_mac: session.remote_mac, source_mac: session.local_mac, ethertype: 0x0800) .push_ipv4_header(packet, total_length: ipv4_total_length, flags: 0x40, protocol: 0x06, source_address: session.local_address, destination_address: session.remote_address) // FIXME: put this into .push_tcp_header Util::push_u16_to_u8_array(packet, session.local_port) Util::push_u16_to_u8_array(packet, session.remote_port) Util::push_u32_to_u8_array(packet, session.local_sequence_number) Util::push_u32_to_u8_array(packet, 0 as! u32) // Acknowledgement number Util::push_u16_to_u8_array(packet, flags) Util::push_u16_to_u8_array(packet, session.last_window_size) Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder Util::push_u16_to_u8_array(packet, 0 as! u16) // Urgent pointer mut tcp_options: [u8] = [0x02, 0x04] Util::push_u16_to_u8_array(tcp_options, .mss_size) Util::push_u32_to_u8_array(tcp_options, 0x0101080a) packet.push_values(&tcp_options) let timestamp: u32 = (session.timestamp_origin + (Time::jiffies() - session.timestamp_origin)) as! u32 Util::push_u32_to_u8_array(packet, timestamp) Util::push_u32_to_u8_array(packet, session.timestamp_last_echo_reply) packet.push(0x01u8) packet.push(0x03u8) packet.push(0x03u8) packet.push(0x07u8) // Calculate TCP checksum mut checksum_packet: [u8] = [] // Source and destination IP for i in 26..34 { checksum_packet.push(packet[i]) } // Protocol checksum_packet.push(0x00u8) checksum_packet.push(0x06u8) // TCP Packet length let tcp_packet_length: u16 = header_length as! u16 Util::push_u16_to_u8_array(checksum_packet, tcp_packet_length) for i in 34..packet.size() { checksum_packet.push(packet[i]) } mut checksum = .calculate_header_checksum(checksum_packet, offset: 0, count: checksum_packet.size() as! i64) packet[50] = (checksum >> 8) as! u8 packet[51] = (checksum & 0xff) as! u8 .tx_queue.push(packet) } fn tcp_psh_packet(mut this, anon mut session: TcpSession) throws { mut packet: [u8] = [] let header_length: u16 = 32 let flags: u16 = 0x8018 // PSH, ACK let maximum_payload_size_to_transmit: i64 = 1024 mut payload_size: i64 = maximum_payload_size_to_transmit let payload_offset: i64 = session.tx_chunk_counter * maximum_payload_size_to_transmit if session.pending_data_to_transmit.size() as! i64 - payload_offset < maximum_payload_size_to_transmit { payload_size = session.pending_data_to_transmit.size() as! i64 - payload_offset } mut ipv4_total_length: u16 = 0 ipv4_total_length += 20; // IPv4 ipv4_total_length += header_length + payload_size as! u16 // TCP .push_ethernet_header(packet, destination_mac: session.remote_mac, source_mac: session.local_mac, ethertype: 0x0800) .push_ipv4_header(packet, total_length: ipv4_total_length, flags: 0x40, protocol: 0x06, source_address: session.local_address, destination_address: session.remote_address) // FIXME: put this into .push_tcp_header Util::push_u16_to_u8_array(packet, session.local_port) Util::push_u16_to_u8_array(packet, session.remote_port) Util::push_u32_to_u8_array(packet, session.local_sequence_number) Util::push_u32_to_u8_array(packet, session.acknowledgement_number) Util::push_u16_to_u8_array(packet, flags) Util::push_u16_to_u8_array(packet, session.last_window_size) Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder Util::push_u16_to_u8_array(packet, 0 as! u16) // Urgent pointer mut tcp_options: [u8] = [0x01, 0x01, 0x08, 0x0a] packet.push_values(&tcp_options) let timestamp: u32 = (session.timestamp_origin + (Time::jiffies() - session.timestamp_origin)) as! u32 Util::push_u32_to_u8_array(packet, timestamp) Util::push_u32_to_u8_array(packet, session.timestamp_last_echo_reply) for i in payload_offset..(payload_offset + payload_size) { packet.push(session.pending_data_to_transmit[i]) } // Calculate TCP checksum mut checksum_packet: [u8] = [] // Source and destination IP for i in 26..34 { checksum_packet.push(packet[i]) } // Protocol checksum_packet.push(0x00u8) checksum_packet.push(0x06u8) // TCP Packet length let tcp_packet_length: u16 = header_length + payload_size as! u16 Util::push_u16_to_u8_array(checksum_packet, tcp_packet_length) for i in 34..packet.size() { checksum_packet.push(packet[i]) } mut checksum = .calculate_header_checksum(checksum_packet, offset: 0, count: checksum_packet.size() as! i64) packet[50] = (checksum >> 8) as! u8 packet[51] = (checksum & 0xff) as! u8 .tx_queue.push(packet) } public fn tcp_transmit_pending_data_for_existing_sessions(mut this) throws { for i in 0..this.tcp_sessions.size() { if .tcp_sessions[i].pending_data_to_transmit.size() > 0 { if (.tcp_sessions[i].tx_chunk_counter == 0) or (.tcp_sessions[i].tx_chunk_counter > 0 and .tcp_sessions[i].last_tx_was_acked) { let maximum_payload_size_to_transmit: i64 = 1024 let payload_offset: i64 = .tcp_sessions[i].tx_chunk_counter * maximum_payload_size_to_transmit mut truncated_packet: [u8] = [] .tcp_psh_packet(.tcp_sessions[i]) if (.tcp_sessions[i].pending_data_to_transmit.size() as! i64 - payload_offset >= maximum_payload_size_to_transmit) { .tcp_sessions[i].last_tx_sequence_number = .tcp_sessions[i].local_sequence_number + maximum_payload_size_to_transmit as! u32 .tcp_sessions[i].last_tx_was_acked = false .tcp_sessions[i].tx_chunk_counter++ } else { // We have transmitted all of the pending data. .tcp_sessions[i].pending_data_to_transmit.shrink(0) .tcp_sessions[i].last_tx_sequence_number = 0 .tcp_sessions[i].last_tx_was_acked = false .tcp_sessions[i].tx_chunk_counter = 0 } } } } } fn tcp_ack_packet(mut this, anon mut session: TcpSession, anon frame: [u8], mut flags: u16) throws -> u32 { mut packet: [u8] = [] let syn_ipv4_packet = frame[14..] let syn_tcp_packet = frame[34..] // Swap source/destination ports mut destination_port: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 0) mut source_port: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 2) let header_length: u16 = ((syn_tcp_packet[12] as! u16) >> 4) * 4 flags += ((header_length / 4) << 12) flags |= 16 // ACK mut sequence_number: u32 = session.local_sequence_number mut acknowledgement_number: u32 = 0 for i in 0..4 { acknowledgement_number += (syn_tcp_packet[7 - i] as! u32) * match i { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } if (.tcp_is_syn(flags) or .tcp_is_fin(flags)) { acknowledgement_number += 1 } if (.tcp_is_push(flags)) { // advance ACK by number of bytes flags -= 8 } acknowledgement_number += (syn_tcp_packet.size() as! u32 - header_length as! u32) let window_size: u16 = 0xffff let urgent_pointer: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 18) mut destination_mac: [u8] = [] for octet in frame[6..12] { destination_mac.push(octet) } mut destination_address: [u8] = [] for octet in syn_ipv4_packet[12..16] { destination_address.push(octet) } mut ipv4_total_length: u16 = 0 ipv4_total_length += 20; // IPv4 ipv4_total_length += header_length // TCP .push_ethernet_header(packet, destination_mac, source_mac: session.local_mac, ethertype: 0x0800) .push_ipv4_header(packet, total_length: ipv4_total_length, flags: 0x40, protocol: 0x06, source_address: .ipv4_address, destination_address) // FIXME: put this into .push_tcp_header Util::push_u16_to_u8_array(packet, source_port) Util::push_u16_to_u8_array(packet, destination_port) Util::push_u32_to_u8_array(packet, sequence_number) Util::push_u32_to_u8_array(packet, acknowledgement_number) Util::push_u16_to_u8_array(packet, flags) Util::push_u16_to_u8_array(packet, window_size) Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder Util::push_u16_to_u8_array(packet, urgent_pointer) mut tcp_options_offset = 20 mut tcp_option_length = 0 while tcp_options_offset < header_length as! i64 { match syn_tcp_packet[tcp_options_offset] { 0u8 => { packet.push(0u8) tcp_options_offset++ } 1u8 => { packet.push(1u8) tcp_options_offset++ } 8u8 => { packet.push(8u8) packet.push(10u8) let timestamp: u32 = (session.timestamp_origin + (Time::jiffies() - session.timestamp_origin)) as! u32 Util::push_u32_to_u8_array(packet, timestamp) Util::push_u32_to_u8_array(packet, session.timestamp_last_echo_reply) tcp_options_offset += 10 } else => { packet.push(syn_tcp_packet[tcp_options_offset]) packet.push(syn_tcp_packet[tcp_options_offset + 1]) tcp_option_length = syn_tcp_packet[tcp_options_offset + 1] as! i64 for i in 2..tcp_option_length { packet.push(syn_tcp_packet[tcp_options_offset + i]) } tcp_options_offset += tcp_option_length } } } // Calculate TCP checksum mut checksum_packet: [u8] = [] // Source and destination IP for i in 26..34 { checksum_packet.push(packet[i]) } // Protocol checksum_packet.push(0x00u8) checksum_packet.push(0x06u8) // TCP Packet length let tcp_packet_length: u16 = 40 as! u16 Util::push_u16_to_u8_array(checksum_packet, tcp_packet_length) for i in 34..packet.size() { checksum_packet.push(packet[i]) } mut checksum = .calculate_header_checksum(checksum_packet, offset: 0, count: checksum_packet.size() as! i64) if (not .tcp_is_syn(flags)) { checksum += 8 } packet[50] = (checksum >> 8) as! u8 packet[51] = (checksum & 0xff) as! u8 .tx_queue.push(packet) return acknowledgement_number } fn tcp_synack_ack_packet(mut this, anon mut session: TcpSession, anon frame: [u8], mut flags: u16) throws -> u32 { mut packet: [u8] = [] let syn_ipv4_packet = frame[14..] let syn_tcp_packet = frame[34..] // Swap source/destination ports mut destination_port: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 0) mut source_port: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 2) let header_length: u16 = (20 + 12) as! u16 flags += ((header_length / 4) << 12) flags |= 16 // ACK mut sequence_number: u32 = session.local_sequence_number mut acknowledgement_number: u32 = 0 for i in 0..4 { acknowledgement_number += (syn_tcp_packet[7 - i] as! u32) * match i { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } acknowledgement_number += 1 let window_size: u16 = 0xffff let urgent_pointer: u16 = Util::get_u16_from_u8_arrayslice(syn_tcp_packet, 18) mut destination_mac: [u8] = [] for octet in frame[6..12] { destination_mac.push(octet) } mut destination_address: [u8] = [] for octet in syn_ipv4_packet[12..16] { destination_address.push(octet) } mut ipv4_total_length: u16 = 0 ipv4_total_length += 20; // IPv4 ipv4_total_length += header_length // TCP .push_ethernet_header(packet, destination_mac, source_mac: session.local_mac, ethertype: 0x0800) .push_ipv4_header(packet, total_length: ipv4_total_length, flags: 0x40, protocol: 0x06, source_address: .ipv4_address, destination_address) // FIXME: put this into .push_tcp_header Util::push_u16_to_u8_array(packet, source_port) Util::push_u16_to_u8_array(packet, destination_port) Util::push_u32_to_u8_array(packet, sequence_number) Util::push_u32_to_u8_array(packet, acknowledgement_number) Util::push_u16_to_u8_array(packet, flags) Util::push_u16_to_u8_array(packet, window_size) Util::push_u16_to_u8_array(packet, 0 as! u16) // Checksum placeholder Util::push_u16_to_u8_array(packet, urgent_pointer) // Options: NOP, NOP, Timestamp packet.push(0x01u8) packet.push(0x01u8) Util::push_u16_to_u8_array(packet, 0x080a) let timestamp: u32 = (session.timestamp_origin + (Time::jiffies() - session.timestamp_origin)) as! u32 Util::push_u32_to_u8_array(packet, timestamp) Util::push_u32_to_u8_array(packet, session.timestamp_last_echo_reply) // Calculate TCP checksum mut checksum_packet: [u8] = [] // Source and destination IP for i in 26..34 { checksum_packet.push(packet[i]) } // Protocol checksum_packet.push(0x00u8) checksum_packet.push(0x06u8) // TCP Packet length let tcp_packet_length: u16 = 40 as! u16 Util::push_u16_to_u8_array(checksum_packet, tcp_packet_length) for i in 34..packet.size() { checksum_packet.push(packet[i]) } mut checksum = .calculate_header_checksum(checksum_packet, offset: 0, count: checksum_packet.size() as! i64) checksum += 8 packet[50] = (checksum >> 8) as! u8 packet[51] = (checksum & 0xff) as! u8 .tx_queue.push(packet) return acknowledgement_number } fn tcp_session_matches_current_session(mut this, anon session: TcpSession, anon local_address: [u8], anon remote_address: [u8], anon local_port: u16, anon remote_port: u16) -> bool { if session.state as! i64 == TcpSessionState::Closed as! i64 { return false } if (session.local_port != local_port) or (session.remote_port != remote_port) { return false } for i in 0..4 { if (session.local_address[i] != local_address[i]) { return false } if (session.remote_address[i] != remote_address[i]) { return false } } return true } fn tcp_send(mut this, anon mut session: TcpSession, anon data: [u8]) throws { session.pending_data_to_transmit.push_values(&data) } public fn tcp_process_client_send_requests(mut this, anon mac_address: [u8]) throws { for i in 0..this.tcp_sessions.size() { let socket = .tcp_sessions[i].socket if socket > 0 { mut data: [u8] = [] unsafe { cpp { "u64 *s = (u64*)socket; if (s[10] == 1) { u8 *buffer = (u8*)s[7]; for (int i=0; i < s[9]; i++) { data.push(buffer[i]); } s[10] = 0; }" } } if data.size() > 0 { .tcp_send(.tcp_sessions[i], data) } } } } public fn tcp_process_client_received_data(mut this) throws { for i in 0..this.tcp_sessions.size() { mut session = .tcp_sessions[i] let socket = session.socket mut length = session.received_data.size() mut max_length: usize = 0 // s[4] = 0; // receive_buffer_size if (socket > 0) { unsafe { cpp { "u64 *s = (u64*)socket; max_length = s[4];" } } } // FIXME: Should the client be responsible for malloc()ing the receive buffer? if length > 65536 { length = 65536 } if (length > max_length) { length = max_length } if (socket > 0) and (length == 0) and (.tcp_sessions[i].state as! i64 == TcpSessionState::Closed as! i64) { .tcp_update_socket_session_state(.tcp_sessions[i].state, .tcp_sessions[i].socket) mut client_is_not_ready_to_receive_data = 0 unsafe { cpp { "u64 *s = (u64*)socket; client_is_not_ready_to_receive_data = s[6];" } } let is_bound_socket = .tcp_sessions[i].is_bound_socket if (not is_bound_socket and client_is_not_ready_to_receive_data == 0) or (is_bound_socket) { // really close the connection unsafe { cpp { "u64 *s = (u64*)socket; s[5] = 0; s[6] = 1; if (s[3] > 0) free((u8*)s[3]); if (s[7] > 0) free((u8*)s[7]); " } } .tcp_sessions[i].socket = 0 } } if socket > 0 and length > 0 { mut client_is_not_ready_to_receive_data = 0 unsafe { cpp { "u64 *s = (u64*)socket; client_is_not_ready_to_receive_data = s[6];" } } if (client_is_not_ready_to_receive_data == 0) { unsafe { cpp { "u64 *s = (u64*)socket; u8 *buffer = (u8*)s[3]; for (int i=0; i < length; i++) { buffer[i] = session.received_data[i]; } s[5] = length; s[6] = 1;" } } if (length == session.received_data.size() as! usize) { session.received_data.shrink(0) } else { mut remaining_received_data: [u8] = [] for j in length..session.received_data.size() { remaining_received_data.push(session.received_data[j]) } session.received_data.shrink(0) for j in 0..remaining_received_data.size() { session.received_data.push(remaining_received_data[j]) } } } } } } fn tcp_is_next_frame(mut this, index: i64, frame: [u8]) throws -> bool { let tcp_packet = frame[34..] mut sequence_number: u32 = 0 for o in 0..4 { sequence_number += (tcp_packet[7 - o] as! u32) * match o { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } if (.tcp_sessions[index].acknowledgement_number == 0) { // session not established yet, we're (hopefully) in a SYN/ACK return true } if (sequence_number == .tcp_sessions[index].acknowledgement_number) { return true } return false } fn tcp_handle_received_frame(mut this, anon i: i64, anon frame: [u8]) throws { let ipv4_packet = frame[14..] let tcp_packet = frame[34..] let total_length = Util::get_u16_from_u8_arrayslice(ipv4_packet, 2) + 14 let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]] let destination_address: [u8] = [ipv4_packet[16], ipv4_packet[17], ipv4_packet[18], ipv4_packet[19]] mut source_port: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 0) mut destination_port: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 2) let header_length: u16 = ((tcp_packet[12] as! u16) >> 4) * 4 let flags: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 12) & 0xfff mut echo_reply: u32 = 0 mut tcp_options_offset = 54 while tcp_options_offset < frame.size() as! i64 { match frame[tcp_options_offset] { 0u8 => { tcp_options_offset++ } 1u8 => { tcp_options_offset++ } 8u8 => { tcp_options_offset++ echo_reply += (frame[tcp_options_offset + 1] as! u32 * (256 * 256 * 256) as! u32) echo_reply += (frame[tcp_options_offset + 2] as! u32 * (256 * 256) as! u32) echo_reply += (frame[tcp_options_offset + 3] as! u32 * 256 as! u32) echo_reply += frame[tcp_options_offset + 4] as! u32 break } else => { tcp_options_offset += frame[tcp_options_offset + 1] as! i64 } } } if (flags & 0xff) != 0x10 { // Received a packet with flags other than just ACK for i in 0..this.tcp_sessions.size() { if (.tcp_session_matches_current_session(.tcp_sessions[i], destination_address, source_address, destination_port, source_port)) { mut received_data: [u8] = [] for j in frame[(34u16 + header_length)..total_length] { received_data.push(j) } for j in 0..received_data.size() { .tcp_sessions[i].received_data.push(received_data[j]) } if (.tcp_is_fin(flags)) { // Received request to close connection //println("Closing connection to IPv4 address: {}", source_address) if (.tcp_is_push(flags)) { .tcp_sessions[i].acknowledgement_number = .tcp_ack_packet(.tcp_sessions[i], frame, flags: 9u16) } else { .tcp_sessions[i].acknowledgement_number = .tcp_ack_packet(.tcp_sessions[i], frame, flags: 1u16) } .tcp_sessions[i].state = TcpSessionState::Closed } else if (.tcp_is_syn(flags)) and (.tcp_is_ack(flags)) { // Received SYN, ACK .tcp_sessions[i].timestamp_last_echo_reply = echo_reply .tcp_sessions[i].timestamp_last_jiffies = Time::jiffies() .tcp_sessions[i].local_sequence_number++ .tcp_sessions[i].acknowledgement_number = .tcp_synack_ack_packet(.tcp_sessions[i], frame, flags: 0u16) .tcp_sessions[i].state = TcpSessionState::Established .tcp_update_socket_session_state(.tcp_sessions[i].state, .tcp_sessions[i].socket) } else { .tcp_sessions[i].timestamp_last_echo_reply = echo_reply .tcp_sessions[i].timestamp_last_jiffies = Time::jiffies() mut acknowledgement_number: u32 = 0 for o in 0..4 { acknowledgement_number += (tcp_packet[11 - o] as! u32) * match o { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } .tcp_sessions[i].local_sequence_number = acknowledgement_number if (.tcp_is_push(flags)) { .tcp_sessions[i].acknowledgement_number = .tcp_ack_packet(.tcp_sessions[i], frame, flags: 8u16) } else { .tcp_sessions[i].acknowledgement_number = .tcp_ack_packet(.tcp_sessions[i], frame, flags: 0u16) } } } } } else if (flags & 0xff) == 0x10 { // Received a packet with flags == just ACK for i in 0..this.tcp_sessions.size() { if (.tcp_session_matches_current_session(.tcp_sessions[i], destination_address, source_address, destination_port, source_port)) { mut received_data: [u8] = [] for j in frame[(34u16 + header_length)..total_length] { received_data.push(j) } for j in 0..received_data.size() { .tcp_sessions[i].received_data.push(received_data[j]) } mut sequence_number: u32 = 0 for o in 0..4 { sequence_number += (tcp_packet[7 - o] as! u32) * match o { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } mut acknowledgement_number: u32 = 0 for o in 0..4 { acknowledgement_number += (tcp_packet[11 - o] as! u32) * match o { 1 => 256 as! u32 2 => (256 * 256) as! u32 3 => (256 * 256 * 256) as! u32 else => 1 as! u32 } } let window_size: u16 = 0xffff if acknowledgement_number == .tcp_sessions[i].last_tx_sequence_number { .tcp_sessions[i].last_tx_was_acked = true } .tcp_sessions[i].local_sequence_number = acknowledgement_number if received_data.size() > 0 { .tcp_sessions[i].acknowledgement_number = .tcp_ack_packet(.tcp_sessions[i], frame, flags: 0u16) } else { .tcp_sessions[i].acknowledgement_number = sequence_number + (received_data.size() as! u32) } .tcp_sessions[i].last_window_size = window_size .tcp_sessions[i].timestamp_last_echo_reply = echo_reply .tcp_sessions[i].timestamp_last_jiffies = Time::jiffies() } } } } fn tcp_handle_received_frames(mut this, anon index: i64) throws { mut unhandled_frames: [[u8]] = [] for frame in .tcp_sessions[index].received_frames { if .tcp_is_next_frame(index, frame) { .tcp_handle_received_frame(index, frame) } else { unhandled_frames.push(frame) } } .tcp_sessions[index].received_frames.shrink(0) for frame in unhandled_frames { .tcp_sessions[index].received_frames.push(frame) } } fn process_udp_packet(mut this, anon mac_address: [u8], anon frame: [u8]) throws { let ipv4_packet = frame[14..] let udp_packet = frame[34..] let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]] let destination_address: [u8] = [ipv4_packet[16], ipv4_packet[17], ipv4_packet[18], ipv4_packet[19]] mut source_port: u16 = Util::get_u16_from_u8_arrayslice(udp_packet, 0) mut destination_port: u16 = Util::get_u16_from_u8_arrayslice(udp_packet, 2) if (Util::get_hexadecimal_string_from_ipv4_u8_array(source_address) == Util::get_hexadecimal_string_from_ipv4_u8_array(.dns_server_address)) and (source_port == .dns_server_port) { let transaction_id: u16 = Util::get_u16_from_u8_arrayslice(udp_packet, 8) let flags: u16 = Util::get_u16_from_u8_arrayslice(udp_packet, 10) // questions : 12-13 // answer_rrs: 14-15 // authority_rrs: 16-17 // additional_rrs: 18-19 if .pending_dns_lookups.contains(transaction_id) { mut result: u32 = 0 mut result_type: u16 = 0 // skip over query data to get answer mut response_pos = 20 while (udp_packet[response_pos] > 0) { response_pos += 1 + udp_packet[response_pos] as! i64 } response_pos += 5 // skip over null byte, type, class response_pos += 2 // skip over answer: name result_type = 256 * udp_packet[response_pos] as! u16 result_type += udp_packet[response_pos + 1] as! u16 mut pointer_to_u32 = .pending_dns_lookups[transaction_id] mut cached_result: [u8] = [] match result_type { 1 => { // A record response_pos += 10 result += (udp_packet[response_pos] as! u32 * (256 * 256 * 256) as! u32) result += (udp_packet[response_pos + 1] as! u32 * (256 * 256) as! u32) result += (udp_packet[response_pos + 2] as! u32 * 256 as! u32) result += udp_packet[response_pos + 3] as! u32 cached_result.push(udp_packet[response_pos]) cached_result.push(udp_packet[response_pos + 1]) cached_result.push(udp_packet[response_pos + 2]) cached_result.push(udp_packet[response_pos + 3]) .dns_cache[.pending_dns_cached_entries[transaction_id]] = cached_result } 5 => { // CNAME record response_pos += 8 // skip over answer: type, class, ttl let data_length = (256 * udp_packet[response_pos] as! i64) + udp_packet[response_pos + 1] as! i64 response_pos += 2 let data_pos = response_pos mut pointer_pos = 0 mut s = StringBuilder::create() mut length = 0 while (response_pos < data_pos + data_length) { match udp_packet[response_pos] { 0xc0 => { response_pos++ pointer_pos = 8 + udp_packet[response_pos++] as! i64 while (udp_packet[pointer_pos] > 0) { length = udp_packet[pointer_pos] as! i64 pointer_pos++ for i in 0..length { s.append(udp_packet[pointer_pos++]) } if udp_packet[pointer_pos] > 0 { s.append('.') } } } else => { length = udp_packet[response_pos++] as! i64 for i in 0..length { s.append(udp_packet[response_pos++]) } if udp_packet[response_pos] > 0 { s.append('.') } } } } .send_dns_query(mac_address, s.to_string(), pointer_to_u32) pointer_to_u32 = 0 } else => { // Unsupported record response_pos += 10 // skip over answer: type, class, ttl, data length result = 0xFFFFFFFF } } if pointer_to_u32 > 0 { unsafe { cpp { "u32 *r = (u32*)pointer_to_u32; r[0] = result;" } } } .pending_dns_lookups.remove(transaction_id) } } } fn is_listening_port(this, anon port: u16) -> bool { return .bound_sockets.contains(port) } fn process_tcp_packet(mut this, anon mac_address: [u8], anon frame: [u8]) throws { let ipv4_packet = frame[14..] let tcp_packet = frame[34..] let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]] let destination_address: [u8] = [ipv4_packet[16], ipv4_packet[17], ipv4_packet[18], ipv4_packet[19]] mut source_port: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 0) mut destination_port: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 2) let header_length: u16 = ((tcp_packet[12] as! u16) >> 4) * 4 let flags: u16 = Util::get_u16_from_u8_arrayslice(tcp_packet, 12) & 0xfff mut echo_reply: u32 = 0 mut tcp_options_offset = 54 while tcp_options_offset < frame.size() as! i64 { match frame[tcp_options_offset] { 0u8 => { tcp_options_offset++ } 1u8 => { tcp_options_offset++ } 8u8 => { tcp_options_offset++ echo_reply += (frame[tcp_options_offset + 1] as! u32 * (256 * 256 * 256) as! u32) echo_reply += (frame[tcp_options_offset + 2] as! u32 * (256 * 256) as! u32) echo_reply += (frame[tcp_options_offset + 3] as! u32 * 256 as! u32) echo_reply += frame[tcp_options_offset + 4] as! u32 break } else => { tcp_options_offset += frame[tcp_options_offset + 1] as! i64 } } } if .tcp_is_syn(flags) and not (.tcp_is_ack(flags)) and (.is_listening_port(destination_port)) { // Received SYN, begin a new connection mut remote_mac: [u8] = [] for i in 6..12 { remote_mac.push(frame[i]) } if .is_local_ipv4_address(source_address) { if not .arp_cache.contains(Util::get_hexadecimal_string_from_ipv4_u8_array(source_address)) { // send arp request //println("send arp request for: {}", Util::get_hexadecimal_string_from_ipv4_u8_array(source_address)) .send_arp_request(mac_address, source_address) } } mut socket: u64 = 0 let function: u64 = .bound_sockets[destination_port] let source_address_u32 = Util::get_address_u32_from_ipv4_u8_array(source_address) unsafe { cpp { " u64* s = (u64*)calloc(256, 1); s[0] = source_address_u32; s[1] = source_port; s[2] = 1; // TCP_SOCKET_STATE_ESTABLISHED s[3] = (u64)calloc(65536, 1); // receive_buffer_ptr s[4] = 0; // receive_buffer_size s[5] = 0; // receive_buffer_filled s[6] = 0; // receive_buffer_kick s[7] = (u64)calloc(65536, 1); // send_buffer_ptr s[8] = 65536; // send_buffer_size s[9] = 0; // send_buffer_filled s[10] = 0; // send_buffer_kick socket = (u64)s; if (function && socket) { os_call(function, socket); } " } } mut session = TcpSession( local_mac: mac_address remote_mac: remote_mac local_address: destination_address remote_address: source_address local_port: destination_port remote_port: source_port local_sequence_number: (OS::random() & 0xffffffff) as! u32 acknowledgement_number: 0 timestamp_last_echo_reply: 0 timestamp_last_jiffies: 0 timestamp_origin: Time::jiffies() last_window_size: 0 last_tx_sequence_number: 0 last_tx_was_acked: false tx_chunk_counter: 0 state: TcpSessionState::Established pending_data_to_transmit: [] received_data: [] received_frames: [] is_bound_socket: true socket) //println("Accepting connection from IPv4 address: {}", source_address) session.timestamp_last_echo_reply = echo_reply session.timestamp_last_jiffies = Time::jiffies() session.acknowledgement_number = .tcp_ack_packet(session, frame, flags) .tcp_sessions.push(session) } else { // Add packet to list to be processed for i in 0..this.tcp_sessions.size() { if (.tcp_session_matches_current_session(.tcp_sessions[i], destination_address, source_address, destination_port, source_port)) { .tcp_sessions[i].received_frames.push(frame) .tcp_handle_received_frames(i as! i64) } } } } public fn process_ipv4_packet(mut this, anon mac_address: [u8], anon frame: [u8]) throws { let ipv4_packet = frame[14..] let version = ipv4_packet[0] >> 4 let header_length = (ipv4_packet[0] as! i64 & 0xf) * 4 let dsf = ipv4_packet[1] let total_length = Util::get_u16_from_u8_arrayslice(ipv4_packet, 2) let identification = Util::get_u16_from_u8_arrayslice(ipv4_packet, 4) let flags = ipv4_packet[6] let ttl = ipv4_packet[8] let protocol = ipv4_packet[9] let checksum = Util::get_u16_from_u8_arrayslice(ipv4_packet, 10) let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]] let destination_address: [u8] = [ipv4_packet[16], ipv4_packet[17], ipv4_packet[18], ipv4_packet[19]] match protocol { 1 => { .process_icmp_packet(mac_address, frame) } 6 => { .process_tcp_packet(mac_address, frame) } 17 => { .process_udp_packet(mac_address, frame) } else => { // unsupported } } } public fn set_ipv4_address(mut this, anon ipv4_address: [i64]) { for i in 0..4 { .ipv4_address[i] = ipv4_address[i] as! u8 } } public fn set_ipv4_netmask(mut this, anon ipv4_netmask: [i64]) { for i in 0..4 { .ipv4_netmask[i] = ipv4_netmask[i] as! u8 } } public fn set_ipv4_network(mut this, anon ipv4_network: [i64]) { for i in 0..4 { .ipv4_network[i] = ipv4_network[i] as! u8 } } public fn set_ipv4_gateway(mut this, anon ipv4_gateway: [i64]) { for i in 0..4 { .ipv4_gateway[i] = ipv4_gateway[i] as! u8 } } fn is_local_ipv4_address(this, anon check_ipv4_address: [u8]) -> bool { let check_ipv4_address_u32 = Util::get_address_u32_from_ipv4_u8_array(check_ipv4_address) let local_network_address_u32 = Util::get_address_u32_from_ipv4_u8_array(.ipv4_network) let local_netmask_address_u32 = Util::get_address_u32_from_ipv4_u8_array(.ipv4_netmask) // NOTE: The line below was added and the subsequent line was modified after jakt PR #1596 to suppress a warning from codegen output // tcpip.cpp:2599:90: warning: & has lower precedence than ==; == will be evaluated first [-Wparentheses] // 2599 | return (local_network_address_u32 & local_netmask_address_u32) == check_ipv4_address_u32 & local_netmask_address_u32; // | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ // tcpip.cpp:2599:90: note: place parentheses around the '==' expression to silence this warning let check_ipv4_address_u32_and_with_netmask = check_ipv4_address_u32 & local_netmask_address_u32 return (local_network_address_u32 & local_netmask_address_u32) == check_ipv4_address_u32_and_with_netmask } fn tcp_update_socket_session_state(mut this, anon state: TcpSessionState, anon socket: u64) throws { unsafe { cpp { "u64 *s = (u64*)socket; s[2] = (u64)state; " } } } public fn tcp_process_bind_request(mut this) { mut did_receive_request = false mut port: u16 = 0 mut function: u64 = 0 mut response_code: u64 = 0 unsafe { cpp { " u64 *request = (u64*)0x300040; if (*request) { did_receive_request = true; u64 *b = (u64*)*request; port = b[0]; function = b[1]; } " } } if did_receive_request { if .bound_sockets.contains(port) { response_code = TcpBindError::SocketIsAlreadyBound as! u64 } else if port < 1 or function < 1 { response_code = TcpBindError::BadRequest as! u64 } else { .bound_sockets[port] = function } unsafe { cpp { " u64 *request = (u64*)0x300040; u64 *b = (u64*)*request; b[2] = response_code; *request = 0; " } } } } public fn tcp_process_client_socket_request(mut this, anon mac_address: [u8]) throws { mut did_receive_request = false mut remote_address: u32 = 0 mut remote_port: u16 = 0 mut session_remote_mac: [u8] = [] mut socket: u64 = 0 unsafe { cpp { "u64 *ls_request = (u64*)0x300000; if (*ls_request) { u64 *ls_s = (u64*)*ls_request; remote_address = ls_s[0]; }" } } if (remote_address > 0) { mut remote_address_hex_string = Util::get_hexadecimal_string_from_ipv4_u8_array(.ipv4_gateway) if .is_local_ipv4_address(Util::get_ipv4_u8_array_from_address_u32(remote_address)) { remote_address_hex_string = Util::get_hexadecimal_string_from_ipv4_u8_array(Util::get_ipv4_u8_array_from_address_u32(remote_address)) if not .arp_cache.contains(remote_address_hex_string) { // send arp request //println("send arp request for: {}", remote_address_hex_string) .send_arp_request(mac_address, Util::get_ipv4_u8_array_from_address_u32(remote_address)) return } } session_remote_mac = .arp_cache[remote_address_hex_string] } else { return } unsafe { cpp { "u64 *request = (u64*)0x300000; if (*request) { did_receive_request = true; u64 *s = (u64*)*request; s[2] = 5; // TCP_SOCKET_STATE_IDLE s[3] = (u64)calloc(65536, 1); // receive_buffer_ptr s[4] = 0; // receive_buffer_size s[5] = 0; // receive_buffer_filled s[6] = 1; // receive_buffer_kick s[7] = (u64)calloc(65536, 1); // send_buffer_ptr s[8] = 65536; // send_buffer_size s[9] = 0; // send_buffer_filled s[10] = 0; // send_buffer_kick remote_address = s[0]; remote_port = s[1]; socket = (u64)s; *request = 0; }" } } if (did_receive_request) { let local_sequence_number: u32 = (OS::random() & 0xffffffff) as! u32 mut session = TcpSession( local_mac: mac_address remote_mac: session_remote_mac local_address: .ipv4_address remote_address: Util::get_ipv4_u8_array_from_address_u32(remote_address) local_port: (OS::random() & 0xffff) as! u16 // FIXME remote_port local_sequence_number acknowledgement_number: 0 timestamp_last_echo_reply: 0 timestamp_last_jiffies: Time::jiffies() timestamp_origin: Time::jiffies() last_window_size: 0xffff last_tx_sequence_number: 0 last_tx_was_acked: false tx_chunk_counter: 0 state: TcpSessionState::Connecting pending_data_to_transmit: [] received_data: [] received_frames: [] is_bound_socket: false socket) .tcp_syn_packet(session) .tcp_update_socket_session_state(session.state, session.socket) .tcp_sessions.push(session) did_receive_request = false } } }