mirror of
https://git.checksum.fail/alec/erythros
synced 2025-12-16 16:09:53 +02:00
1675 lines
68 KiB
Plaintext
1675 lines
68 KiB
Plaintext
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 <u16>((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<u32>().value()
|
|
u32_address += octets[2].to_number<u32>().value() << 8
|
|
u32_address += octets[1].to_number<u32>().value() << 16
|
|
u32_address += octets[0].to_number<u32>().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
|
|
}
|
|
}
|
|
} |