From 20484c6adae2b357533e7d01d755851bdf6f853b Mon Sep 17 00:00:00 2001 From: TomAwezome Date: Fri, 7 Aug 2020 02:39:07 -0400 Subject: [PATCH] Network stack in functional state Many TODOs and still a good bit of tidying up to do PCNet Direct Init wasn't working so added Shrine/OSDev Initialization Block code, need to do renames and comments for clarity Added UDPRep and ARPRep as early network Rep functions. UDPRep to see all bound sockets still needs to be made To get the network stack running, #include NetStart.CC --- ...o => Zenith-latest-2020-08-07-02_32_46.iso | Bin 34392064 -> 34422784 bytes src/Home/Net/ARP.CC | 64 ++- src/Home/Net/DHCP.CC | 534 ++++++++++++++++++ src/Home/Net/DNS.CC | 250 +++++++- src/Home/Net/Docs/ZenithStackNotes.DD | Bin 3052 -> 3083 bytes src/Home/Net/Ethernet.CC | 4 +- src/Home/Net/ICMP.CC | 6 +- src/Home/Net/IPV4.CC | 49 +- src/Home/Net/Net.HH | 2 +- src/Home/Net/NetHandlerTask.CC | 13 +- src/Home/Net/NetQueue.CC | 14 +- src/Home/Net/NetStart.CC | 28 + src/Home/Net/PCNet.CC | 186 ++++-- src/Home/Net/Sockets.CC | 39 +- src/Home/Net/Tests/DHCPTest1.CC | 4 + src/Home/Net/Tests/DNSTest1.CC | 16 + src/Home/Net/Tests/MakeBreakDown.CC | 33 ++ src/Home/Net/Tests/UDPSendTrash.CC | 21 + src/Home/Net/UDP.CC | 128 +++-- 19 files changed, 1227 insertions(+), 164 deletions(-) rename Zenith-latest-2020-07-31-13_42_17.iso => Zenith-latest-2020-08-07-02_32_46.iso (99%) create mode 100755 src/Home/Net/DHCP.CC create mode 100755 src/Home/Net/NetStart.CC create mode 100755 src/Home/Net/Tests/DHCPTest1.CC create mode 100755 src/Home/Net/Tests/DNSTest1.CC create mode 100755 src/Home/Net/Tests/MakeBreakDown.CC create mode 100755 src/Home/Net/Tests/UDPSendTrash.CC diff --git a/Zenith-latest-2020-07-31-13_42_17.iso b/Zenith-latest-2020-08-07-02_32_46.iso similarity index 99% rename from Zenith-latest-2020-07-31-13_42_17.iso rename to Zenith-latest-2020-08-07-02_32_46.iso index 21d6020473a8629551a44a8eb0d77a2b78e6b9b8..302a7aabc399376408202a94f4b1497a40e01de5 100755 GIT binary patch delta 69591 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 Nigfv5+}^xK_&?#5kWByp delta 42482 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 diff --git a/src/Home/Net/ARP.CC b/src/Home/Net/ARP.CC index b24a829f..76d39c43 100755 --- a/src/Home/Net/ARP.CC +++ b/src/Home/Net/ARP.CC @@ -1,5 +1,5 @@ -#include "PCNet" -#include "Ethernet" +//#include "PCNet" +//#include "Ethernet" #define ARP_HASHTABLE_SIZE 1024 @@ -54,8 +54,9 @@ I64 ARPSend(U16 operation, U32 target_ip) {//method currently assumes send_ and target_ip EndianU16 already... - U8 *ethernet_frame; - CARPHeader *header; + U8 *ethernet_frame; + CARPHeader *header; + I64 de_index = EthernetFrameAllocate(ðernet_frame, send_mac_address, dest_mac_address, @@ -85,10 +86,14 @@ I64 ARPSend(U16 operation, CARPHash *ARPCacheFindByIP(U32 ip_address) { - U8 *ip_string = MStrPrint("%d", ip_address); - CARPHash *entry = HashFind(ip_string, arp_cache, HTT_ARP); + U8 *ip_string = MStrPrint("%X", ip_address); + CARPHash *entry = HashFind(ip_string, arp_cache, HTT_ARP); + if (entry == NULL) - ZenithErr("Could not find an IP in ARP cache."); + { + ZenithWarn("ARP CACHE FIND BY IP: Could not find an IP in ARP cache.\n"); +// CallerRep; + } Free(ip_string); return entry; @@ -96,19 +101,24 @@ CARPHash *ARPCacheFindByIP(U32 ip_address) CARPHash *ARPCachePut(U32 ip_address, U8 *mac_address) { + ZenithLog("ARP CACHE PUT: Attempting to look for entry in ARP Cache.\n"); CARPHash *entry = ARPCacheFindByIP(ip_address); //Free(entry); // something seems wrong about this... if (!entry) { entry = CAlloc(sizeof(CARPHash)); - entry->str = MStrPrint("%d", ip_address); + ZenithLog("ARP CACHE PUT: Attempting add to cache: addr, mac: \n"); + ZenithLog(" 0x%0X, 0x%0X 0x%0X 0x%0X 0x%0X 0x%0X 0x%0X\n", + ip_address, mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); + entry->str = MStrPrint("%X", ip_address); + entry->type = HTT_ARP; MemCopy(entry->mac_address, mac_address, 6); HashAdd(entry, arp_cache); } else - ZenithWarn("ARP Cache Put attempted but entry was already found in Cache. TODO: overwrite?\n"); + ZenithWarn("ARP CACHE Put: Entry was already found in Cache. TODO: overwrite?\n"); return entry; } @@ -139,16 +149,18 @@ U0 ARPSetIPV4Address(U32 ip_address) //the NetQueueHandler I64 ARPHandler(CEthernetFrame *ethernet_frame) { + ZenithLog("ARP HANDLER: Entering ARP Handler.\n"); + // shrine checks if frame ethertype is ARP and ensures length is not less than CARPHeader // since revising Shrine implement, will do same checks for now .. if (ethernet_frame->ethertype != ETHERTYPE_ARP) { - ZenithErr("ARP Handler caught wrong frame ethertype."); + ZenithErr("ARP HANDLER: Caught wrong frame ethertype.\n"); return -1; // External use of ARPHandler must account for -1 error codes } if (ethernet_frame->length < sizeof(CARPHeader)) { - ZenithErr("ARP Handler caught wrong frame length."); + ZenithErr("ARP HANDLER: Caught wrong frame length.\n"); return -1; // External use of ARPHandler must account for -1 error codes } @@ -161,22 +173,22 @@ I64 ARPHandler(CEthernetFrame *ethernet_frame) // hlen(?) != 6(?), and that plen(?) == 4 (?) if (EndianU16(header->hardware_type) != HTYPE_ETHERNET) { - ZenithErr("ARP Handler caught wrong frame hardware type."); + ZenithErr("ARP HANDLER: Caught wrong frame hardware type.\n"); return -1; // External use of ARPHandler must account for -1 error codes } if (EndianU16(header->protocol_type) != ETHERTYPE_IPV4) { - ZenithErr("ARP Handler caught wrong frame protocol type."); + ZenithErr("ARP HANDLER: Caught wrong frame protocol type.\n"); return -1; // External use of ARPHandler must account for -1 error codes } if (header->hardware_addr_len != HLEN_ETHERNET) { - ZenithErr("ARP Handler caught wrong frame hardware address length."); + ZenithErr("ARP HANDLER: Caught wrong frame hardware address length.\n"); return -1; // External use of ARPHandler must account for -1 error codes } if (header->protocol_addr_len != PLEN_IPV4) { - ZenithErr("ARP Handler caught wrong frame protocol address length."); + ZenithErr("ARP HANDLER: Caught wrong frame protocol address length.\n"); return -1; // External use of ARPHandler must account for -1 error codes } @@ -197,4 +209,26 @@ I64 ARPHandler(CEthernetFrame *ethernet_frame) } } +U0 ARPRep() +{ // TODO: primitive, needs refine. + I64 i; + CARPHash *temp_hash; + + "\n"; + Who(, arp_cache); + "\n"; + + for (i = 0; i <= arp_cache->mask; i++) + { + temp_hash = arp_cache->body[i]; + + while (temp_hash) + { + ClassRep(temp_hash); + temp_hash = temp_hash->next; + } + } +} + + ARPCacheInit; \ No newline at end of file diff --git a/src/Home/Net/DHCP.CC b/src/Home/Net/DHCP.CC new file mode 100755 index 00000000..318ad14c --- /dev/null +++ b/src/Home/Net/DHCP.CC @@ -0,0 +1,534 @@ +//www.networksorcery.com/enp/protocol/dhcp.htm + +//#include "DNS"; + +#define DHCP_OPCODE_BOOTREQUEST 0x01 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS 6 +#define DHCP_OPTION_DOMAIN_NAME 15 + +#define DHCP_OPTION_REQUESTED_IP 50 +#define DHCP_OPTION_MESSAGETYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_PARAMLIST 55 + +#define DHCP_MESSAGETYPE_DISCOVER 0x01 +#define DHCP_MESSAGETYPE_OFFER 0x02 +#define DHCP_MESSAGETYPE_REQUEST 0x03 +#define DHCP_MESSAGETYPE_ACK 0x05 + +#define DHCP_COOKIE 0x63825363 + +#define DHCP_STATE_CLIENT_START 0 +#define DHCP_STATE_CLIENT_DISCOVER 1 +#define DHCP_STATE_CLIENT_REQUEST 2 +#define DHCP_STATE_CLIENT_REQ_ACCEPTED 3 + +#define DHCP_TIMEOUT 3000 +#define DHCP_MAX_RETRIES 5 // shrine has 3, why not 5 :^) + +class CDHCPHeader +{ + U8 opcode; // Opcode + U8 hw_type; // Hardware Type + U8 hw_addr_len; // Hardware Address Length + U8 hops; // Hop Count + U32 xid; // Transaction ID + U16 seconds; // Elapsed time in seconds since client began address acquisition or renewal process + U16 flags; // Flags + U32 client_ip; // Client IP Address + U32 your_ip; // Your IP Address + U32 server_ip; // Server IP Address + U32 gateway_ip; // Gateway IP Address + U8 client_hw_addr[16]; // Client Hardware Address + U8 server_name[64]; // Server Hostname + U8 boot_file[128]; // Boot Filename +}; + +class CDHCPDiscoverOptions +{ + U32 cookie; + U8 message_type; + U8 message_length; + U8 message; // dmt + U8 param_req_list_type; + U8 param_req_list_length; + U8 param_req_list[4]; + U8 end; +}; + +class CDHCPRequestOptions +{ + U32 cookie; + U8 message_type; + U8 message_length; + U8 message; // dmt + U8 requested_ip_type; + U8 requested_ip_length; + U32 requested_ip; + U8 server_id_type; + U8 server_id_length; + U32 server_id; + U8 end; +}; + +U32 DHCPBeginTransaction() +{ + return RandU32(); +} + +I64 DHCPSendDiscover(U32 xid) +{ + U8 *ethernet_frame; + I64 de_index; + CDHCPHeader *dhcp; + CDHCPDiscoverOptions *opts; + + + de_index = UDPPacketAllocate(ðernet_frame, + 0x00000000, + 68, + 0xFFFFFFFF, + 67, + sizeof(CDHCPHeader) + sizeof(CDHCPDiscoverOptions)); + if (de_index < 0) + { + ZenithErr("DHCP SEND DISCOVER: Failed, UDP Packet Allocate error.\n"); + return de_index; + } + + dhcp = ethernet_frame; + MemSet(dhcp, 0, sizeof(CDHCPHeader)); + + dhcp->opcode = DHCP_OPCODE_BOOTREQUEST; + dhcp->hw_type = HTYPE_ETHERNET; + dhcp->hw_addr_len = HLEN_ETHERNET; + dhcp->hops = 0; + dhcp->xid = EndianU32(xid); + dhcp->seconds = 0; + dhcp->flags = EndianU16(0x8000); // TODO: what is this + dhcp->client_ip = 0; + dhcp->your_ip = 0; + dhcp->server_ip = 0; + dhcp->gateway_ip = 0; + MemCopy(dhcp->client_hw_addr, EthernetGetMAC(), MAC_ADDRESS_LENGTH); +// "DHCP Send Discover\n"; +// ClassRep(dhcp); + + opts = ethernet_frame + sizeof(CDHCPHeader); + + opts->cookie = EndianU32(DHCP_COOKIE); + opts->message_type = DHCP_OPTION_MESSAGETYPE; + opts->message_length = 1; + opts->message = DHCP_MESSAGETYPE_DISCOVER; + opts->param_req_list_type = DHCP_OPTION_PARAMLIST; + opts->param_req_list_length = 4; + opts->param_req_list[0] = DHCP_OPTION_SUBNET_MASK; + opts->param_req_list[1] = DHCP_OPTION_ROUTER; + opts->param_req_list[2] = DHCP_OPTION_DNS; + opts->param_req_list[3] = DHCP_OPTION_DOMAIN_NAME; + opts->end = 0xFF; // ?? +// ClassRep(opts); + + UDPPacketFinish(de_index); + return de_index; +} + +I64 DHCPSendRequest(U32 xid, U32 requested_ip, U32 server_ip) +{ + U8 *ethernet_frame; + I64 de_index; + CDHCPHeader *dhcp; + CDHCPRequestOptions *opts; + + de_index = UDPPacketAllocate(ðernet_frame, + 0x00000000, + 68, + 0xFFFFFFFF, + 67, + sizeof(CDHCPHeader) + sizeof(CDHCPRequestOptions)); + if (de_index < 0) + { + ZenithErr("DHCP SEND REQUEST: Failed, UDP Packet Allocate error.\n"); + } + + dhcp = ethernet_frame; + MemSet(dhcp, 0, sizeof(CDHCPHeader)); + + dhcp->opcode = DHCP_OPCODE_BOOTREQUEST; + dhcp->hw_type = HTYPE_ETHERNET; + dhcp->hw_addr_len = HLEN_ETHERNET; + dhcp->hops = 0; + dhcp->xid = EndianU32(xid); + dhcp->seconds = 0; + dhcp->flags = EndianU16(0x0000); // seems redundant ... + dhcp->client_ip = 0; + dhcp->your_ip = 0; + dhcp->server_ip = EndianU32(server_ip); + dhcp->gateway_ip = 0; + MemCopy(dhcp->client_hw_addr, EthernetGetMAC(), MAC_ADDRESS_LENGTH); + + opts = ethernet_frame + sizeof(CDHCPHeader); + + opts->cookie = EndianU32(DHCP_COOKIE); + opts->message_type = DHCP_OPTION_MESSAGETYPE; + opts->message_length = 1; + opts->message = DHCP_MESSAGETYPE_REQUEST; + opts->requested_ip_type = DHCP_OPTION_REQUESTED_IP; + opts->requested_ip_length = 4; + opts->requested_ip = EndianU32(requested_ip); + opts->server_id_type = DHCP_OPTION_SERVER_ID; + opts->server_id_length = 4; + opts->server_id = EndianU32(server_ip); + opts->end = 0xFF; + +// ClassRep(opts); + UDPPacketFinish(de_index); + return 0; +} + +I64 DHCPParseBegin(U8 **data_inout, I64 *length_inout, CDHCPHeader **header_out) +{ + U8 *data = *data_inout; + I64 length = *length_inout; + U32 *cookie; + + if (length < sizeof(CDHCPHeader) + 4) // + 4? + { + ZenithErr("DHCP PARSE BEGIN: Failed, length too short.\n"); + return -1; + } + + cookie = data + sizeof(CDHCPHeader); + + if (EndianU32(*cookie) != DHCP_COOKIE) + { + ZenithErr("DHCP PARSE BEGIN: Failed, cookie doesn't match DHCP-cookie.\n"); + return -1; + } + + *header_out = data; + *data_inout = data + sizeof(CDHCPHeader) + 4; // ? + *length_inout = length - sizeof(CDHCPHeader) + 4; // ?.. + + return 0; +} + +I64 DHCPParseOption(U8 **data_inout, I64 *length_inout, U8 *type_out, U8 *value_length_out, U8 **value_out) +{ + U8 *data = *data_inout; + I64 length = *length_inout; + + if (length < 2 || length < 2 + data[1]) // ??? what is the 1 + { + ZenithErr("DHCP PARSE OPTION: Failed, length too short.\n"); + return -1; + } + + if (data[0] == 0xFF) // ahead, data[0] is type_out, so data[0] is perhaps usually type? + { + ZenithLog("DHCP PARSE OPTION: Saw 0xFF, returning 0.\n"); + return 0; + } + + *type_out = data[0]; + *value_length_out = data[1]; + *value_out = data + 2; + + *data_inout = data + 2 + *value_length_out; + *length_inout = length - 2 + *value_length_out; + + return data[0]; // returns ... type? +} + +I64 DHCPParseOffer(U32 xid, U8 *data, I64 length, + U32 *your_ip_out, + U32 *dns_ip_out, + U32 *router_ip_out, + U32 *subnet_mask_out) +{ + CDHCPHeader *header; + I64 error = DHCPParseBegin(&data, &length, &header); + Bool have_type = FALSE; + Bool have_dns = FALSE; + Bool have_router = FALSE; + Bool have_subnet = FALSE; + U8 type; + U8 value_length; + U8 *value; + + + if (EndianU32(header->xid) != xid) + { + ZenithErr("DHCP PARSE OFFER: Failed, parsed and parameter Transaction IDs do not match.\n"); + return -1; + } + + while (length) + { + error = DHCPParseOption(&data, &length, &type, &value_length, &value); + + if (error < 0) + { + ZenithErr("DHCP PARSE OFFER: Failed at DHCP Parse Option.\n"); + return error; + } + if (error == 0) + { + break; + } + + switch (type) + { + case DHCP_OPTION_MESSAGETYPE: + ZenithLog("DHCP PARSE OFFER: Parsed Option, Type MESSAGETYPE.\n"); + if (value_length == 1 && value[0] == DHCP_MESSAGETYPE_OFFER) + have_type = TRUE; + break; + + case DHCP_OPTION_DNS: + ZenithLog("DHCP PARSE OFFER: Parsed Option, Type DNS.\n"); + if (value_length == 4) + { + *dns_ip_out = EndianU32(*(value(U32 *))); // TODO: this syntax used on last 3 cases is gross, alter it + have_dns = TRUE; + } + break; + + case DHCP_OPTION_ROUTER: + ZenithLog("DHCP PARSE OFFER: Parsed Option, Type ROUTER.\n"); + if (value_length == 4) + { + *router_ip_out = EndianU32(*(value(U32 *))); // + have_router = TRUE; + } + break; + + case DHCP_OPTION_SUBNET_MASK: + ZenithLog("DHCP PARSE OFFER: Parsed Option, Type SUBNET MASK.\n"); + if (value_length == 4) + { + *subnet_mask_out = EndianU32(*(value(U32 *))); // + have_subnet = TRUE; + } + break; + } + } + + if (have_type && have_dns && have_subnet && have_router) + { + *your_ip_out = EndianU32(header->your_ip); + ZenithLog("DHCP PARSE OFFER: Success, got your-ip from DHCP Header.\n"); + return 0; + } + else + { + ZenithErr("DHCP PARSE OFFER: Failed, did not have needed Options.\n"); + ZenithErr(" have_type: %Z\n", have_type, "ST_FALSE_TRUE"); + ZenithErr(" have_dns: %Z\n", have_dns, "ST_FALSE_TRUE"); + ZenithErr(" have_router: %Z\n", have_router, "ST_FALSE_TRUE"); + ZenithErr(" have_subnet: %Z\n", have_subnet, "ST_FALSE_TRUE"); + return -1; + } +} + +I64 DHCPParseAck(U32 xid, U8 *data, I64 length) +{ + CDHCPHeader *header; + I64 error = DHCPParseBegin(&data, &length, &header); + U8 type; + U8 value_length; + U8 *value; + + if (EndianU32(header->xid) != xid) + { + ZenithErr("DHCP PARSE ACK: Failed, parsed and parameter Transaction IDs do not match.\n"); + return -1; + } + + while (length) + { + error = DHCPParseOption(&data, &length, &type, &value_length, &value); + + if (error < 0) + { + ZenithErr("DHCP PARSE ACK: Failed at DHCP Parse Option.\n"); + return error; + } + if (error == 0) + { + break; + } + + switch (type) + { + case DHCP_OPTION_MESSAGETYPE: + if (value_length == 1 && value[0] == DHCP_MESSAGETYPE_ACK) + return 0; + break; + } + } + + ZenithErr("DHCP PARSE ACK: Failed.\n"); + return -1; +} + +I64 DHCPConfigureInner(CUDPSocket *udp_socket, + U32 *your_ip_out, + U32 *dns_ip_out, + U32 *router_ip_out, + U32 *subnet_mask_out) +{ + I64 state = DHCP_STATE_CLIENT_START; + I64 retries = 0; + I64 timeout = DHCP_TIMEOUT; + I64 error = 0; + U32 xid; + U32 dhcp_addr; + U8 buffer[2048]; + I64 count; + + CSocketAddressIPV4 ipv4_addr; + CSocketAddressIPV4 ipv4_addr_in; + + //Shrine: setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO_MS, &timeout, sizeof(timeout))) + udp_socket->receive_timeout_ms = timeout; + + ipv4_addr.family = AF_INET; + ipv4_addr.port = EndianU16(68); + ipv4_addr.address.address = INADDR_ANY; + + if (UDPSocketBind(udp_socket, &ipv4_addr) < 0) + { + ZenithErr("DHCP CONFIGURE INNER: Failed to Bind UDP Socket.\n"); + return -1; + } + + xid = DHCPBeginTransaction(); + + while (state != DHCP_STATE_CLIENT_REQ_ACCEPTED) + { + switch (state) + { + case DHCP_STATE_CLIENT_START: + state = DHCP_STATE_CLIENT_DISCOVER; + retries = 0; + + break; + + case DHCP_STATE_CLIENT_DISCOVER: + ZenithLog("DHCP CONFIGURE INNER: Trying Discover.\n"); + error = DHCPSendDiscover(xid); + if (error < 0) + { + ZenithErr("DHCP CONFIGURE INNER: Failed, DHCP Send Discover error.\n"); + return error; + } + + count = UDPSocketReceiveFrom(udp_socket, buffer, sizeof(buffer), &ipv4_addr_in); + + if (count > 0) + { // 'Try a parse offer' + ZenithLog("DHCP CONFIGURE INNER: Trying Parse Offer.\n"); + error = DHCPParseOffer(xid, buffer, count, your_ip_out, dns_ip_out, router_ip_out, subnet_mask_out); + + if (error < 0) + ZenithWarn("DHCP CONFIGURE INNER: Unsuccessful DHCP Parse Offer.\n"); + } + + if (count > 0 && error >= 0) // TODO: >= ? can DHCPSendDiscover or DHCPParseOffer return greater than zero? + { + dhcp_addr = EndianU32(ipv4_addr_in.address.address); + state = DHCP_STATE_CLIENT_REQUEST; + retries = 0; + } + else if (++retries == DHCP_MAX_RETRIES) + { + ZenithErr("DHCP CONFIGURE INNER: Failed, hit max retries in DHCP DISCOVER state.\n"); + return -1; + } + + break; + + case DHCP_STATE_CLIENT_REQUEST: + ZenithLog("DHCP CONFIGURE INNER: Trying Send Request.\n"); + error = DHCPSendRequest(xid, *your_ip_out, dhcp_addr); + + if (error < 0) + { + ZenithErr("DHCP CONFIGURE INNER: Failed, unsuccessful DHCP Send Request.\n"); + return error; + } + + count = UDPSocketReceiveFrom(udp_socket, buffer, sizeof(buffer), &ipv4_addr_in); + + if (count > 0) + { // 'Try parse Ack' + error = DHCPParseAck(xid, buffer, count); + + if (error < 0) + ZenithWarn("DHCP CONFIGURE INNER: Unsuccessful DHCP Parse Ack.\n"); + } + + if (count > 0 && error >= 0) // see above TODO + { + dhcp_addr = EndianU32(ipv4_addr_in.address.address); + state = DHCP_STATE_CLIENT_REQ_ACCEPTED; + } + else if (++retries == DHCP_MAX_RETRIES) + { + ZenithErr("DHCP CONFIGURE INNER: Failed, hit max retries in DHCP REQUEST state.\n"); + return -1; + } + + break; + } + } + + return state; +} + +I64 DHCPConfigure() +{ + CUDPSocket *udp_socket = UDPSocket(AF_INET); + CIPV4Address address; + U32 your_ip; + U32 dns_ip; + U32 router_ip; + U32 subnet_mask; + I64 state = DHCPConfigureInner(udp_socket, &your_ip, &dns_ip, &router_ip, &subnet_mask); + + UDPSocketClose(udp_socket); + + if (state == DHCP_STATE_CLIENT_REQ_ACCEPTED) + { + address.address = EndianU32(your_ip); + ZenithLog("$$FG,2$$DHCP CONFIGURE: Obtained IPV4 Address! : %s $$FG$$\n", NetworkToPresentation(AF_INET, &address)); + + IPV4SetAddress(your_ip); + IPV4SetSubnet(router_ip, subnet_mask); + DNSSetResolverIPV4(dns_ip); + return 0; + } + else + { + ZenithErr("$$FG,4$$DHCP CONFIGURE: Failed, incorrect state.$$FG$$\n"); + return -1; + } +} + + +U0 NetConfigure() +{ + I64 error; + + ZenithLog("==== Configuring Network. ====\n"); + error = DHCPConfigure(); + + if (error < 0) + ZenithLog("$$FG,4$$==== Network Configure Failed ====$$FG$$\n"); + else + ZenithLog("$$FG,2$$==== Network Configure Success ====$$FG$$\n"); +} diff --git a/src/Home/Net/DNS.CC b/src/Home/Net/DNS.CC index 6fb6d86d..a73bab0e 100755 --- a/src/Home/Net/DNS.CC +++ b/src/Home/Net/DNS.CC @@ -1,4 +1,4 @@ -#include "UDP"; +//#include "UDP"; // https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf // https://en.wikipedia.org/wiki/Domain_Name_System @@ -17,6 +17,9 @@ #define DNS_CLASS_IN 1 #define DNS_TIMEOUT 5000 + +#define DNS_MAX_RETRIES 5 // Shrine has 3, why not 5? :^) + class CDNSHash:CHash { // store U8 *hostname as CHash->str U8 * CAddressInfo info; @@ -82,25 +85,30 @@ CDNSHash *DNSCacheFind(U8 *hostname) CDNSHash *entry = HashFind(hostname, dns_cache, HTT_DNS); if (entry == NULL) - ZenithErr("Could not find a hostname in the DNS Cache.\n"); + ZenithWarn("DNS CACHE FIND: Could not find a hostname in the DNS Cache.\n"); return entry; } CDNSHash *DNSCachePut(U8 *hostname, CAddressInfo *info) { + ZenithLog("DNS CACHE PUT: Attempting Find DNS Entry in Cache: hostname: %s\n", hostname); +/* "==\n";ClassRep(info); + ClassRep(info->address(CSocketAddressIPV4 *));"==\n";*/ CDNSHash *entry = DNSCacheFind(hostname); if (!entry) { entry = CAlloc(sizeof(CDNSHash)); - entry->str = StrNew(hostname); + entry->str = StrNew(hostname); + entry->type = HTT_DNS; + AddressInfoCopy(&entry->info, info); HashAdd(entry, dns_cache); } else - ZenithWarn("DNS Cache Put attempted but entry was already found in Cache. TODO: overwrite?"); + ZenithWarn("DNS CACHE PUT: Entry was already found in Cache. TODO: overwrite?"); return entry; } @@ -150,17 +158,21 @@ I64 DNSSendQuestion(U16 id, U16 local_port, CDNSQuestion *q) switch (dns_globals.addr_family) { case AF_UNSPEC: // 0, global dns ip not set + ZenithErr("DNS SEND QUESTION: Failed, global dns addr family was AF_UNSPEC.\n"); return -1; case AF_INET6: - ZenithErr("IPV6 not supported yet in DNS.\n"); + ZenithErr("DNS SEND QUESTION: Failed, IPV6 not supported yet in DNS.\n"); throw('DNS'); case AF_INET: ipv4_addr = &dns_globals.dns_ip; if (!*ipv4_addr) + { + ZenithErr("DNS SEND QUESTION: Failed, ipv4_addr had no value set.\n"); return -1; + } } // UDPPacketAllocate currently only accepts IPV4 ... @@ -171,7 +183,10 @@ I64 DNSSendQuestion(U16 id, U16 local_port, CDNSQuestion *q) 53, sizeof(CDNSHeader) + DNSCalculateQuestionSize(q)); if (de_index < 0) + { + ZenithErr("DNS SEND QUESTION: Failed, UDPPacketAllocate returned error.\n"); return de_index; + } flags = (DNS_OP_QUERY << 11) | DNS_FLAG_RD; @@ -202,7 +217,7 @@ I64 DNSParseDomainName(U8 *packet_data, I64 packet_length, U8 **data_inout, I64 if (length < 1) { - ZenithErr("DNS parsed domain name, hit length of 0 or less\n"); + ZenithErr("DNS PARSE DOMAIN NAME: Length less than one.\n"); return -1; } @@ -228,7 +243,7 @@ I64 DNSParseDomainName(U8 *packet_data, I64 packet_length, U8 **data_inout, I64 *data_inout = data + 1; *length_inout = length - 1; jump_taken = TRUE; - ZenithLog("UDP parsed domain name, jump taken\n"); + ZenithLog("DNS PARSE DOMAIN NAME: Jump taken\n"); } data = packet_data + ((label_len << 8) | *data); @@ -317,7 +332,7 @@ I64 DNSParseRR(U8 *packet_data, I64 packet_length, U8 **data_inout, I64 *length_ return 0; } -I64 DNSParseResponse(U16 id, U8 *data, I64 len, CDNSHeader **header_out, CDNSQuestion **questions_out, CDNSRR **answers_out) +I64 DNSParseResponse(U16 id, U8 *data, I64 length, CDNSHeader **header_out, CDNSQuestion **questions_out, CDNSRR **answers_out) { CDNSHeader *header; CDNSQuestion *question; @@ -328,7 +343,7 @@ I64 DNSParseResponse(U16 id, U8 *data, I64 len, CDNSHeader **header_out, CDNSQue if (length < sizeof(CDNSHeader)) { - ZenithErr("DNS Response Parsed, length too short.\n"); + ZenithErr("DNS PARSE RESPONSE: Length too short.\n"); return -1; } @@ -337,7 +352,7 @@ I64 DNSParseResponse(U16 id, U8 *data, I64 len, CDNSHeader **header_out, CDNSQue if (id != 0 && EndianU16(header->id) != id) { - ZenithErr("DNS Response Parsed, header id mismatch.\n"); + ZenithErr("DNS PARSE RESPONSE: Header ID mismatch.\n"); return -1; } @@ -399,7 +414,7 @@ U0 DNSFreeQuestion(CDNSQuestion *q) Free(q->q_name.labels[0]); } -U0 DNSFreeRR(CDNSRR *r) +U0 DNSFreeRR(CDNSRR *rr) { Free(rr->name.labels[0]); } @@ -430,17 +445,18 @@ U0 DNSFreeRRChain(CDNSRR *rrs) } } -/* + I64 DNSRunQuery(CUDPSocket *udp_socket, U8 *name, U16 port, CAddressInfo **result_out) -{ // IPV4-UDP-based +{ // IPV4-UDP-based, TODO: take good look at this method to ensure no floating pointers after. + // note: UDP Socket created in this method is not closed in this method, gets closed e.g. in DNSGetAddressInfo I64 retries = 0; I64 timeout = DNS_TIMEOUT; - U16 local_port = RandU16; + U16 local_port = RandU16; // TODO: is rand needed? would a local port 0 work? (would improve lookup speed) U16 id = RandU16; I64 error = 0; - U8 *buffer; + U8 buffer[2048]; I64 count; - Bool have; + Bool have; // ?? CDNSQuestion q; CDNSHeader *header; @@ -450,24 +466,214 @@ I64 DNSRunQuery(CUDPSocket *udp_socket, U8 *name, U16 port, CAddressInfo **resul CSocketAddressIPV4 ipv4_addr; CSocketAddressIPV4 ipv4_addr_in; // ? + CSocketAddressIPV4 *ipv4_addr_temp; CAddressInfo *res; //setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO_MS, &timeout, sizeof(timeout)) udp_socket->receive_timeout_ms = timeout; - + ipv4_addr.family = AF_INET; + ipv4_addr.port = EndianU16(local_port); + ipv4_addr.address.address = INADDR_ANY; + // UDPSocketBind will be attempted on the udp_socket param, method expects a UDPSocket() result to be made already + if (UDPSocketBind(udp_socket, &ipv4_addr)) // expected return value is 0 + { + ZenithErr("DNS RUN QUERY: Failed to bind UDP socket.\n"); + return -1; + } + + DNSBuildQuestion(&q, name); + + while (TRUE) // Shrine uses while (1) infinite loop, need to be careful not to lock + { + error = DNSSendQuestion(id, local_port, &q); + if (error < 0) + { + ZenithErr("DNS RUN QUERY: Failed to Send Question.\n"); + return -1; + } + + count = UDPSocketReceiveFrom(udp_socket, buffer, sizeof(buffer), &ipv4_addr_in); + + if (count > 0) + { + ZenithLog("DNS RUN QUERY: Trying Parse Response.\n"); + + header = NULL; + questions = NULL; + answers = NULL; + + error = DNSParseResponse(id, buffer, count, &header, &questions, &answers); + + if (error == 0) // Shrine has (error >= 0), but DNSParseResponse can only return 0 or 1 .. + { + have = FALSE; + + a = answers; + while (a) + { + // Shrine has TODO: if multiple acceptable answers, pick one at random, not just first one. + // perhaps we could use r_count in header for that ? + + if (EndianU16(a->type) == DNS_TYPE_A && + EndianU16(a->rr_class) == DNS_CLASS_IN && + EndianU16(a->rd_length) == 4) + { + res = CAlloc(sizeof(CAddressInfo)); + + res->flags = 0; + res->family = AF_INET; + res->socket_type = 0; // ?? + res->protocol = 0; // ?? + res->address_length = sizeof(CSocketAddressIPV4); + res->address = CAlloc(sizeof(CSocketAddressIPV4)); + res->canonical_name = 0; + res->next = NULL; + + ipv4_addr_temp = res->address; + + ipv4_addr_temp->family = AF_INET; + ipv4_addr_temp->port = port; + MemCopy(&ipv4_addr_temp->address.address, answers->r_data, 4); + + DNSCachePut(name, res); + *result_out = res; + have = TRUE; + + break; + } + + a = a->next; + } + + DNSFreeQuestionChain(questions); + DNSFreeRRChain(answers); + + if (have) + break; + + // Shrine comment: 'at this point, we could try iterative resolution, + // but all end-user DNS servers would have tried that already' + + ZenithErr("DNS RUN QUERY: Failed to find suitable answer in reply.\n"); + error = -1; + } + else + { + ZenithErr("DNS RUN QUERY: Failed a DNS Parse Response.\n"); + } + } + + if (++retries == DNS_MAX_RETRIES) + { + ZenithErr("DNS RUN QUERY: Failed, max retries reached.\n"); + error = -1; + break; + } + } + + DNSFreeQuestion(&q); + return error; } -*/ -/* -I64 DNSRunQuery(socket?, U8 *name, U16 port, CAddressInfo **result_out) +// Shrine has port arg as U8 *service with a no_warn and says it should be parsed as port, allowing that here +// Also has CAddressInfo *hints with a no_warn, omitting that for now +I64 DNSGetAddressInfo(U8 *node_name, U16 port, CAddressInfo **result) +{ + I64 error; + CUDPSocket *udp_socket; + CDNSHash *cached_entry = DNSCacheFind(node_name); -I64 DNSGetAddressInfo(U8 *node, U8 *service, CAddressInfo *hints, CAddressInfo **result) + if (cached_entry) + { + *result = CAlloc(sizeof(CAddressInfo)); + AddressInfoCopy(*result, &cached_entry->info); + //(*res)->flags |= AI_CACHED; // TODO: add AI_CACHED define (maybe a better name?) not used anywhere i don't think.. + return 0; + } -U0 DNSSetResolverIPV4(U32 ip) // funny enough he explicitly labeled IPV4......... + udp_socket = UDPSocket(AF_INET); + error = 0; + + if (udp_socket) + { + error = DNSRunQuery(udp_socket, node_name, port, result); + + UDPSocketClose(udp_socket); + } + else + { + ZenithErr("DNS GET ADDRESS INFO: Failed to make UDP Socket.\n"); + error = -1; + } + + return error; +} + +U0 DNSSetResolverIPV4(U32 ip) +{ + CIPV4Address *address = &dns_globals.dns_ip; + + dns_globals.addr_family = AF_INET; + address->address = ip; +} U0 Host(U8 *hostname) +{ // getaddrinfo() for whole system in Shrine ends up as pointer to DNSGetAddressInfo.. should we do something similar? + CAddressInfo *current; + CAddressInfo *result = NULL; + I64 error = DNSGetAddressInfo(hostname, NULL, &result); + I64 i = 0; + + if (error < 0) + { + ZenithErr("HOST(): Failed at DNS Get Address Info.\n"); + } + else + { + "Host() Results:\n\n"; + current = result; + while (current) + { + "Result %d:\n", ++i; + + " flags: %04Xh \n", current->flags; + " family: %d \n", current->family; + " socket type: %d \n", current->socket_type; + " protocol: %d \n", current->protocol; + " address length: %d \n", current->address_length; + " address: %s \n", NetworkToPresentation(AF_INET, ¤t->address(CSocketAddressIPV4 *)->address); + + current = current->next; + } + } + + AddressInfoFree(result); +} + +U0 DNSRep() +{ // TODO: primitive, needs refine. switch() on Socket Address types for NetworkToPresentation, etc + I64 i; + CDNSHash *temp_hash; + + "\n"; + Who(, dns_cache); + "\n"; + + for (i = 0; i <= dns_cache->mask; i++) + { + temp_hash = dns_cache->body[i]; + + while (temp_hash) + { + ClassRep(temp_hash,, 5); + temp_hash = temp_hash->next; + } + } +} + +/* U0 DNSInit() diff --git a/src/Home/Net/Docs/ZenithStackNotes.DD b/src/Home/Net/Docs/ZenithStackNotes.DD index f4f4a4f4c0cbaa9863635412738d7442197d3a9a..91b82a8b1abb577e2f46710790531edec201db3f 100755 GIT binary patch delta 44 ycmaDO-Yv0V4HKjD=Cw>(j1n?O7#SGOF)%Q=csK_zNG%5PE&zFZH(y|u;Q#;~iwm&; delta 19 bcmeB{cq6`H4HKiv=Cw>(jGMnPi*f(}NP7l= diff --git a/src/Home/Net/Ethernet.CC b/src/Home/Net/Ethernet.CC index bd24e620..ce63381b 100755 --- a/src/Home/Net/Ethernet.CC +++ b/src/Home/Net/Ethernet.CC @@ -36,6 +36,8 @@ U0 EthernetFrameParse(CEthernetFrame *frame_out, U8 *frame, U16 length) //of the current system should be done with less extra allocation //altogether, more passing. + ZenithLog("ETHERNET FRAME PARSE: Parsing frame, copying out to frame_out param.\n"); + MemCopy(frame_out->destination_address, frame, MAC_ADDRESS_LENGTH); MemCopy(frame_out->source_address, frame + MAC_ADDRESS_LENGTH, MAC_ADDRESS_LENGTH); @@ -44,7 +46,7 @@ U0 EthernetFrameParse(CEthernetFrame *frame_out, U8 *frame, U16 length) frame_out->data = frame + ETHERNET_DATA_OFFSET; - frame_out->length = length - ETHERNET_MAC_HEADER_LENGTH + 4; // He has a comment literally just saying "??". + frame_out->length = length - ETHERNET_MAC_HEADER_LENGTH - 4; // He has a comment literally just saying "??". + or - 4? } EthernetInitGlobals; \ No newline at end of file diff --git a/src/Home/Net/ICMP.CC b/src/Home/Net/ICMP.CC index a9496179..99b87248 100755 --- a/src/Home/Net/ICMP.CC +++ b/src/Home/Net/ICMP.CC @@ -1,4 +1,4 @@ -#include "IPV4" +//#include "IPV4" #define ICMP_TYPE_ECHO_REPLY 0 #define ICMP_TYPE_ECHO_REQUEST 8 @@ -32,7 +32,7 @@ I64 ICMPSendReply(U32 destination_ip_address, sizeof(CICMPHeader) + length); if (de_index < 0) { - ZenithLog("ICMP Send Reply failed to allocate IPV4 packet.\n"); + ZenithErr("ICMP SEND REPLY: Failed to allocate IPV4 packet.\n"); return de_index; } @@ -57,7 +57,7 @@ I64 ICMPHandler(CIPV4Packet *packet) if (packet->length < sizeof(CICMPHeader)) { - ZenithLog("ICMP Handler caught wrong IPV4 length.\n"); + ZenithErr("ICMP HANDLER: Caught wrong IPV4 length.\n"); return -1; } diff --git a/src/Home/Net/IPV4.CC b/src/Home/Net/IPV4.CC index 35dbcf85..70f03071 100755 --- a/src/Home/Net/IPV4.CC +++ b/src/Home/Net/IPV4.CC @@ -1,4 +1,4 @@ -#include "ARP" +//#include "ARP" #define IPV4_ERR_ADDR_INVALID -200001 #define IPV4_ERR_HOST_UNREACHABLE -200002 @@ -42,7 +42,7 @@ class CIPV4Header U32 source_ip_address; U32 destination_ip_address; -} +}; class CIPV4Globals { // _be indicates Big Endian @@ -60,7 +60,7 @@ U0 InitIPV4Globals() ipv4_globals.local_ip_be = 0; ipv4_globals.ipv4_router_address = 0; ipv4_globals.ipv4_subnet_mask = 0; -} +}; // For now, trusting Shrine's implement // of checksum. Shrine links back to @@ -96,25 +96,26 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out) CARPHash *entry; I64 retries; I64 attempt; -/* - switch (ip_address) - { - case 0: - return IPV4_ERR_ADDR_INVALID; - case 0xFFFFFFFF: - *mac_out = ethernet_globals.ethernet_broadcast; - return 0; - } -*/ + if (ip_address == 0) { - ZenithLog("Get MAC for IP failed. Address = 0\n"); + ZenithErr("GET MAC FOR IP: Failed. Address = 0\n"); return IPV4_ERR_ADDR_INVALID; } if (ip_address == 0xFFFFFFFF) { - ZenithLog("Get MAC for IP requested and returning ethernet broadcast\n"); + ZenithLog("GET MAC FOR IP: Returning ethernet broadcast\n"); *mac_out = ethernet_globals.ethernet_broadcast; + +/* I64 i; + "\nEthernet Global Broadcast\n"; + for (i = 0; i < 6; i++) + " %X", ethernet_globals.ethernet_broadcast[i]; + "\nMac Out\n"; + for (i = 0; i < 6; i++) + " %X", (*mac_out)[i]; + "\n"; +*/ return 0; } @@ -122,9 +123,12 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out) if ((ip_address & ipv4_globals.ipv4_subnet_mask) != (ipv4_globals.local_ip & ipv4_globals.ipv4_subnet_mask)) { // TODO: Shrine recurses here... and says FIXME infinite loop if mis-configured... + ZenithWarn("GET MAC FOR IP: TODO: Doing GetMACAddressForIP recursion, could infinite loop and overflow stack."); + return GetMACAddressForIP(ipv4_globals.ipv4_router_address, mac_out); } else // "local network" { + ZenithLog("GET MAC FOR IP: Attempting ARP Find by IP for address: %d.\n", ip_address); entry = ARPCacheFindByIP(ip_address); if (entry) @@ -138,6 +142,13 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out) retries = 4; while (retries) { + ARPSend(ARP_REQUEST, + ethernet_globals.ethernet_broadcast, + EthernetGetMAC, + ipv4_globals.local_ip_be, + ethernet_globals.ethernet_null, + EndianU32(ip_address)); + attempt = 0; for (attempt = 0; attempt < 50; attempt++) { @@ -157,7 +168,7 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out) } //Shrine does some in_addr mess to log error - ZenithLog("Failed to resolve address %d", ip_address); + ZenithErr("GET MAC FOR IP: Failed to resolve address %d\n", ip_address); return IPV4_ERR_HOST_UNREACHABLE; } } @@ -179,7 +190,7 @@ I64 IPV4PacketAllocate(U8 **frame_out, if (error < 0) { - ZenithLog("IPV4 Packet Allocate failed to get MAC for destination.\n"); + ZenithLog("IPV4 PACKET ALLOCATE: Failed to get MAC for destination.\n"); return error; } @@ -190,7 +201,7 @@ I64 IPV4PacketAllocate(U8 **frame_out, sizeof(CIPV4Header) + length); if (de_index < 0) { - ZenithLog("IPV4 Ethernet Frame Allocate failed.\n"); + ZenithLog("IPV4 PACKET ALLOCATE: Ethernet Frame Allocate failed.\n"); return de_index; } @@ -208,7 +219,7 @@ I64 IPV4PacketAllocate(U8 **frame_out, header->header_checksum = 0; // why is 0 ok? header->source_ip_address = EndianU32(source_ip_address); header->destination_ip_address = EndianU32(destination_ip_address); - header->header_checksum = IPV4Checksum(header, internet_header_length + 4);//why the 4's... + header->header_checksum = IPV4Checksum(header, internet_header_length * 4);//why the 4's... *frame_out = ethernet_frame + sizeof(CIPV4Header); return de_index; diff --git a/src/Home/Net/Net.HH b/src/Home/Net/Net.HH index 8b0e6af6..23700426 100755 --- a/src/Home/Net/Net.HH +++ b/src/Home/Net/Net.HH @@ -8,7 +8,7 @@ /* Ethernet Frame Size. Linux uses 1544, OSDev and Shrine use 1548. Based on IEEE 802.3as, max frame size was agreed upon as 2000 bytes. */ -#define ETHERNET_FRAME_SIZE 2000 +#define ETHERNET_FRAME_SIZE 2048//2000 #define HTYPE_ETHERNET 1 #define HLEN_ETHERNET 6 diff --git a/src/Home/Net/NetHandlerTask.CC b/src/Home/Net/NetHandlerTask.CC index 16267c47..e8eab401 100755 --- a/src/Home/Net/NetHandlerTask.CC +++ b/src/Home/Net/NetHandlerTask.CC @@ -9,13 +9,13 @@ U0 IPV4Handler(CEthernetFrame *ethernet_frame) switch (packet.protocol) { case IP_PROTOCOL_ICMP: - ZenithLog("IPV4 Handler: ICMP.\n"); + ZenithLog("IPV4 HANDLER: ICMP.\n"); ICMPHandler(&packet); break; case IP_PROTOCOL_TCP: break; case IP_PROTOCOL_UDP: - ZenithLog("IPV4 Handler: UDP.\n"); + ZenithLog("IPV4 HANDLER: UDP.\n"); UDPHandler(&packet); break; } @@ -30,9 +30,11 @@ U0 HandleNetQueueEntry(CNetQueueEntry *entry) switch (ethernet_frame.ethertype) { case ETHERTYPE_ARP: + ZenithLog("HANDLE NETQUEUE ENTRY: ARP.\n"); ARPHandler(ðernet_frame); break; case ETHERTYPE_IPV4: + ZenithLog("HANDLE NETQUEUE ENTRY: IPV4.\n"); IPV4Handler(ðernet_frame); break; } @@ -42,10 +44,11 @@ U0 NetHandlerTask(I64) { while (TRUE) { - CNetQueueEntry *entry = NetQueuePull; + CNetQueueEntry *entry = NetQueuePull(); if (entry) { + ZenithLog("NET HANDLER TASK: Caught NetQueue Entry, handling.\n"); HandleNetQueueEntry(entry); } else @@ -56,6 +59,8 @@ U0 NetHandlerTask(I64) } } + ZenithErr("Net Handler Task exit! Debug!\n"); // shouldn't ever reach this } -net_handler_task = Spawn(&NetHandlerTask, NULL, "NetQueueHandler",,); \ No newline at end of file +net_handler_task = Spawn(&NetHandlerTask, NULL, "NetQueueHandler"); + diff --git a/src/Home/Net/NetQueue.CC b/src/Home/Net/NetQueue.CC index a9eaea81..3c05ede7 100755 --- a/src/Home/Net/NetQueue.CC +++ b/src/Home/Net/NetQueue.CC @@ -13,6 +13,7 @@ class CNetQueueEntry:CQueue U8 frame[ETHERNET_FRAME_SIZE]; }; + /* global variable, holds pointer of Ethernet Queue. This acts as the Head of the Queue, Entries act as the Tail of the Queue. @@ -21,11 +22,14 @@ class CNetQueueEntry:CQueue CQueue *net_queue; // no QueueRemove the Head! only Entries! + /* Net Handler Task is set idle and active depending on if entries in Net Queue. See $LK,"NetHandlerTask",A="FF:C:/Home/Net/NetHandlerTask.CC,net_handler_task"$ */ CTask *net_handler_task = NULL; + + U0 NetQueueInit() { net_queue = CAlloc(sizeof(CQueue)); @@ -35,11 +39,14 @@ U0 NetQueueInit() CNetQueueEntry *NetQueuePull() {/* Returns a pointer to a CNetQueueEntry, or NULL pointer if Net Queue is empty. */ + CNetQueueEntry *entry; if (net_queue->next != net_queue) { entry = net_queue->next; + + ZenithLog("NETQUEUE PULL: Removing entry from queue.\n"); QueueRemove(entry); } else // Queue is empty if head->next is head itself. @@ -55,19 +62,20 @@ U0 NetQueuePushCopy(U8 *data, I64 length) into the Net Queue. The NetQueueEntry is inserted after the last entry of net_queue to keep new items in the back of the Queue, old in front. */ + CNetQueueEntry *entry = CAlloc(sizeof(CNetQueueEntry)); entry->length = length; + MemCopy(entry->frame, data, length); QueueInsert(entry, net_queue->last); //Set Net Handler Task active. - ZenithLog("ACTIVE: NetHandler\n"); + ZenithLog("NETQUEUE PUSH COPY: Setting NetHandler ACTIVE.\n"); if (net_handler_task) LBtr(&net_handler_task->task_flags, TASKf_IDLE); - - } + NetQueueInit; \ No newline at end of file diff --git a/src/Home/Net/NetStart.CC b/src/Home/Net/NetStart.CC new file mode 100755 index 00000000..cf44f72b --- /dev/null +++ b/src/Home/Net/NetStart.CC @@ -0,0 +1,28 @@ +#include "C:/Home/Net/Net.HH" + +#include "C:/Home/Net/NetQueue" +#include "C:/Home/Net/PCNet" +#include "C:/Home/Net/Ethernet" + +#include "C:/Home/Net/ARP" +#include "C:/Home/Net/IPV4" +#include "C:/Home/Net/ICMP" + +#include "C:/Home/Net/Sockets" + +#include "C:/Home/Net/UDP" + +#include "C:/Home/Net/DNS" +#include "C:/Home/Net/DHCP" + +#include "C:/Home/Net/NetHandlerTask" // needs IPV4, UDP, ICMP + + + +XTalk(Fs, "NetConfigure;\n"); + +XTalk(Fs, "Host(\"zenithos.org\");\n"); + +XTalk(Fs, "DNSRep;\n"); + +XTalk(Fs, "ARPRep;\n"); diff --git a/src/Home/Net/PCNet.CC b/src/Home/Net/PCNet.CC index 56cfd478..717f1b26 100755 --- a/src/Home/Net/PCNet.CC +++ b/src/Home/Net/PCNet.CC @@ -13,8 +13,8 @@ - Clear documentation. */ -#include "Net.HH" -#include "NetQueue" +//#include "Net.HH" +//#include "NetQueue" #define PCNET_DEVICE_ID 0x2000 #define PCNET_VENDOR_ID 0x1022 @@ -53,7 +53,9 @@ #define PCNET_CSR_RXRINGLEN 76 #define PCNET_CSR_TXRINGLEN 78 -#define PCNET_SWSTYLE_SELECTION 2 // AMD PCNet datasheet p. 1-968 +#define PCNET_SWSTYLE_SELECTION 2 // (value, not bit) AMD PCNet datasheet p. 1-968 + +#define PCNET_SWSTYLE_SSIZE32 8 // Bit 8 of SWSTYLE // Refer to AMD PCNet datasheet p. 1-954, 1-956, 1-957 for Interrupt Mask details. #define PCNET_INT_BSWP 2 // Byte Swap (Big-Endian / Little-Endian) @@ -110,9 +112,21 @@ class CPCNetDescriptorEntry U32 reserved; }; +class CPCNetBufferSetup +{ + U16 mode; + U8 rlen; + U8 tlen; + U8 mac[6]; + U16 reserved; + U8 ladr[8]; + U32 rxbuf; + U32 txbuf; +}; CPCIDev *PCNetPCIDevFind() {// Find and return PCNetII card as a CPCIDev pointer. + return PCIDevFind(,, PCNET_VENDOR_ID, PCNET_DEVICE_ID); } @@ -121,6 +135,7 @@ U32 PCNetGetIOBase() of PCNet card. Bits 0-4 are not for the IO base, so an AND with ~0x1F ignores those bits. */ + U32 io_base = pcnet.pci->base[0] & ~0x1F; return io_base; } @@ -129,8 +144,9 @@ U0 PCNetReset() {/* Reads the 32- and 16-bit RESET registers, which, regardless of which mode the card is in, will reset it back to 16-bit mode. */ - InU32(PCNetGetIOBase + PCNET_DW_RESET); - InU16(PCNetGetIOBase + PCNET_WD_RESET); + + InU32(PCNetGetIOBase() + PCNET_DW_RESET); + InU16(PCNetGetIOBase() + PCNET_WD_RESET); Busy(5); // OSDev says minimum 1 ęS } @@ -139,8 +155,8 @@ U0 PCNetEnter32BitMode() Summary: A 32-bit write (while in 16-bit mode) to RDP will cause 16-bit mode exit and immediate enter into 32-bit mode. */ - OutU32(PCNetGetIOBase + PCNET_DW_RDP, 0); + OutU32(PCNetGetIOBase() + PCNET_DW_RDP, 0); } U0 PCNetWriteRAP(U32 value) @@ -148,7 +164,8 @@ U0 PCNetWriteRAP(U32 value) Summary: Register Address Pointer register value will indicate which CSR / BCR register we want to access in RDP / BDP. */ - OutU32(PCNetGetIOBase + PCNET_DW_RAP, value); + + OutU32(PCNetGetIOBase() + PCNET_DW_RAP, value); } U0 PCNetWriteCSR(U32 csr, U32 value) @@ -157,8 +174,9 @@ U0 PCNetWriteCSR(U32 csr, U32 value) accessed via the RDP (Register Data Port). Which CSR is selected is based on the value in the RAP. */ + PCNetWriteRAP(csr); - OutU32(PCNetGetIOBase + PCNET_DW_RDP, value); + OutU32(PCNetGetIOBase() + PCNET_DW_RDP, value); } U32 PCNetReadCSR(U32 csr) @@ -167,8 +185,9 @@ U32 PCNetReadCSR(U32 csr) accessed via the RDP (Register Data Port). Which CSR is selected is based on the value in the RAP. */ + PCNetWriteRAP(csr); - return InU32(PCNetGetIOBase + PCNET_DW_RDP); + return InU32(PCNetGetIOBase() + PCNET_DW_RDP); } U0 PCNetSetSWStyle() @@ -179,10 +198,13 @@ U0 PCNetSetSWStyle() initialization block. In PCINet-PCI mode, CSR4 bits function as defined in the datasheet , and TMD1[29] functions as ADD_FCS. */ + U32 csr = PCNetReadCSR(PCNET_CSR_SOFTWARESTYLE); - csr &= ~0xFF; // clears first 8 bits: SWSTYLE 8-bit register. +// csr &= ~0xFF; // clears first 8 bits: SWSTYLE 8-bit register. + csr &= 0xFFF0; csr |= PCNET_SWSTYLE_SELECTION; // set SWSTYLE to PCNet-PCI mode. + Bts(&csr, PCNET_SWSTYLE_SSIZE32); // set SSIZE32 bit 1 PCNetWriteCSR(PCNET_CSR_SOFTWARESTYLE, csr); } @@ -192,11 +214,16 @@ U0 PCNetGetMAC() MAC address stored at first 6 bytes of PCNet EEPROM. EEPROM addresses shadow-copied to APROM at hardware init. APROM accessible at first 16 bytes of PCI IO space. */ + I64 i; + ZenithLog("PCNET GET MAC: Getting VM MAC.\n"); + ZenithLog(" "); for (i = 0; i < 6; i++) { - pcnet.mac_address[i] = InU8(PCNetGetIOBase + i); + pcnet.mac_address[i] = InU8(PCNetGetIOBase() + i); + ZenithLog(" %02X", pcnet.mac_address[i]); } + ZenithLog("\n"); } U0 PCNetInitDescriptorEntry(CPCNetDescriptorEntry *entry, U32 buffer_address, I64 is_rx) @@ -208,6 +235,7 @@ U0 PCNetInitDescriptorEntry(CPCNetDescriptorEntry *entry, U32 buffer_address, I6 12 bits of 2s-complement of desired length. Bits 0-11 of a DE are for the buffer byte count (BCNT), and bits 12-15 of a DE must be written all ones (ONES) */ + U16 buffer_byte_count = -ETHERNET_FRAME_SIZE; // Sets up as 2s complement of the desired length. buffer_byte_count &= 0x0FFF; // Masks 0 over everything except bits 0-11. @@ -217,8 +245,8 @@ U0 PCNetInitDescriptorEntry(CPCNetDescriptorEntry *entry, U32 buffer_address, I6 //if this is a Receive DE, give ownership to the card so the PCNet can fill them. if (is_rx) Bts(&entry->status1, PCNET_DESCRIPTORf_OWN); - ClassRep(entry); - + +// ClassRep(entry); } U0 PCNetAllocateBuffers() @@ -228,6 +256,7 @@ U0 PCNetAllocateBuffers() /* AMD PCNet datasheet p.1-913, p.1-990 When SSIZE32=1, Descriptor Ring Entry Base Address must be on 16-byte boundary. (TDRA[3:0]=0, RDRA[3:0]=0) */ + pcnet.rx_de_buffer_phys = CAllocAligned(sizeof(CPCNetDescriptorEntry) * PCNET_RX_BUFF_COUNT, 16, Fs->code_heap); @@ -253,17 +282,23 @@ U0 PCNetAllocateBuffers() CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer; for (de_index = 0; de_index < PCNET_RX_BUFF_COUNT; de_index++) { - PCNetInitDescriptorEntry(&entry[de_index], pcnet.rx_buffer_addr, TRUE); // TRUE for is_rx. + //PCNetInitDescriptorEntry(&entry[de_index], pcnet.rx_buffer_addr, TRUE); // TRUE for is_rx. + PCNetInitDescriptorEntry(&entry[de_index], + pcnet.rx_buffer_addr + de_index * ETHERNET_FRAME_SIZE, + TRUE); // TRUE for is_rx. } entry = pcnet.tx_de_buffer; for (de_index = 0; de_index < PCNET_TX_BUFF_COUNT; de_index++) { - PCNetInitDescriptorEntry(&entry[de_index], pcnet.tx_buffer_addr, FALSE); // FALSE for is_rx. + //PCNetInitDescriptorEntry(&entry[de_index], pcnet.tx_buffer_addr, FALSE); // FALSE for is_rx. + PCNetInitDescriptorEntry(&entry[de_index], + pcnet.tx_buffer_addr + de_index * ETHERNET_FRAME_SIZE, + FALSE); // FALSE for is_rx. } - } +/* U0 PCNetDirectInit() {/* AMD PCNet datasheet p. 1-1021 Instead of setting up initialization block, @@ -288,8 +323,11 @@ U0 PCNetDirectInit() The OR and bit-shift of 8 allows writing separate U8 values in the correct locations of the CSR. */ + ZenithLog("PCNetDirectInit: Write MAC to CSR: 0x%X \n", pcnet.mac_address[0] | (pcnet.mac_address[1] << 8)); PCNetWriteCSR(PCNET_CSR_PADR0, pcnet.mac_address[0] | (pcnet.mac_address[1] << 8)); + ZenithLog("PCNetDirectInit: Write MAC to CSR: 0x%X \n", pcnet.mac_address[2] | (pcnet.mac_address[3] << 8)); PCNetWriteCSR(PCNET_CSR_PADR1, pcnet.mac_address[2] | (pcnet.mac_address[3] << 8)); + ZenithLog("PCNetDirectInit: Write MAC to CSR: 0x%X \n", pcnet.mac_address[4] | (pcnet.mac_address[5] << 8)); PCNetWriteCSR(PCNET_CSR_PADR2, pcnet.mac_address[4] | (pcnet.mac_address[5] << 8)); /* AMD PCNet datasheet p.1-961, 1-962, 1-963 @@ -333,8 +371,29 @@ U0 PCNetDirectInit() as zeroes read undefined. */ PCNetWriteCSR(PCNET_CSR_RXRINGLEN, -PCNET_RX_BUFF_COUNT & 0xFFFF); PCNetWriteCSR(PCNET_CSR_TXRINGLEN, -PCNET_TX_BUFF_COUNT & 0xFFFF); +} +*/ +U8 *PCNetInitBlockSetup() +{ + U8 *setup = CAlloc(sizeof(CPCNetBufferSetup), Fs->code_heap); + CPCNetBufferSetup *u_setup = setup + dev.uncached_alias; + U32 p_setup; + + u_setup->mode = 0; + u_setup->rlen = 5 << 4; + u_setup->tlen = 3 << 4; + MemCopy(u_setup->mac, pcnet.mac_address, 6); + u_setup->reserved = 0; + MemSet(u_setup->ladr, 0, 8); + u_setup->rxbuf = pcnet.rx_de_buffer_phys; + u_setup->txbuf = pcnet.tx_de_buffer_phys; + + p_setup = setup; + PCNetWriteCSR(1, p_setup & 0xFFFF); + PCNetWriteCSR(2, p_setup >> 16); + return setup; } U0 PCNetSetInterruptCSR() @@ -344,6 +403,7 @@ U0 PCNetSetInterruptCSR() We set Big-Endian disabled, RX interrupts enabled, Init Done interrupt disabled, and TX interrupt disabled. */ + U32 csr = PCNetReadCSR(PCNET_CSR_INTERRUPTS); Btr(&csr, PCNET_INT_BSWP); @@ -360,12 +420,12 @@ U0 PCNetEnableTXAutoPad() Setting bit 11 (Auto Pad Transmit) allows shoft transmit frames to be automatically extended to 64 bytes. */ + U32 csr = PCNetReadCSR(PCNET_CSR_FEATURECTRL); Bts(&csr, PCNET_FEATURE_APADXMT); PCNetWriteCSR(PCNET_CSR_FEATURECTRL, csr); - } U0 PCNetExitConfigMode() @@ -375,6 +435,7 @@ U0 PCNetExitConfigMode() and STOP are cleared and START bit is set, in Status and Control Register (CSR0). */ + U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); Btr(&csr, PCNET_CTRL_INIT); @@ -382,14 +443,15 @@ U0 PCNetExitConfigMode() Bts(&csr, PCNET_CTRL_STRT); + PCNetWriteCSR(PCNET_CSR_CTRLSTATUS, csr); } I64 PCNetDriverOwns(CPCNetDescriptorEntry* entry) {/* Returns whether the value of the OWN bit of the Descriptor Entry is zero. If 0, driver owns, if 1, PCNet card owns it. */ - return !Bt(&entry->status1, PCNET_DESCRIPTORf_OWN); + return !Bt(&entry->status1, PCNET_DESCRIPTORf_OWN); } I64 PCNetAllocateTransmitPacket(U8 **packet_buffer_out, I64 length) @@ -405,18 +467,22 @@ I64 PCNetAllocateTransmitPacket(U8 **packet_buffer_out, I64 length) if (length > 0xFFF) { // Max packet length must fit into BCNT 12-bit register. - ZenithErr("Invalid TX Packet Length"); + ZenithErr("PCNET ALLOCATE TX PACKET: Invalid TX Packet Length\n"); throw('PCNet'); } - - CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index]; +// CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index]; + CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index * sizeof(CPCNetDescriptorEntry)]; if (!PCNetDriverOwns(entry)) { - ZenithErr("TX FIFO Full"); + ZenithErr("PCNET ALLOCATE TX PACKET: TX FIFO Full\n"); return -1; // Positive value expected. Functions calling this must factor this in. } + else + { + ZenithLog("PCNET ALLOCATE TX PACKET: Driver owns TX DE at index %d.\n", de_index); + } Bts(&entry->status1, PCNET_DESCRIPTORf_STP); @@ -437,16 +503,21 @@ I64 PCNetAllocateTransmitPacket(U8 **packet_buffer_out, I64 length) *packet_buffer_out = pcnet.tx_buffer_addr + (de_index * ETHERNET_FRAME_SIZE); + ZenithLog("PCNET ALLOCATE TX PACKET: de_index: %X.\n", de_index); return de_index; - } U0 PCNetFinishTransmitPacket(I64 de_index) {/* Release ownership of the packet to the PCNet card by setting the OWN bit to 1. */ - CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index]; + +// CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index]; + CPCNetDescriptorEntry *entry = &pcnet.tx_de_buffer[de_index * sizeof(CPCNetDescriptorEntry)]; Bts(&entry->status1, PCNET_DESCRIPTORf_OWN); + ZenithLog("PCNet FINISH TX PACKET: TX DE index: %X, OWN bit of entry at entry: %b.\n", + de_index, Bt(&entry->status1, PCNET_DESCRIPTORf_OWN)); +// CallerRep; } @@ -465,10 +536,12 @@ I64 PCNetReceivePacket(U8 **packet_buffer_out, U16 *packet_length_out) The increment of the current RX DE index is done by assigning it the value of incrementing it AND the max DE index-1. This will increment it as well as wrap back to 0 if we hit the max DE index. */ - ZenithErr("PCNet received packet. %X , %X",packet_buffer_out,packet_length_out); + + ZenithLog("PCNET RECEIVE PACKET: PCNet received packet. %X , %X \n", packet_buffer_out, packet_length_out); I64 de_index = pcnet.current_rx_de_index; - CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index]; +// CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index]; + CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index * sizeof(CPCNetDescriptorEntry)]; U16 packet_length = entry->status2 & 0xFFFF; @@ -477,15 +550,16 @@ I64 PCNetReceivePacket(U8 **packet_buffer_out, U16 *packet_length_out) *packet_buffer_out = pcnet.rx_buffer_addr + (de_index * ETHERNET_FRAME_SIZE); *packet_length_out = packet_length; - return de_index; - + return de_index; } U0 PCNetReleaseReceivePacket(I64 de_index) {/* Release ownership of the packet to the PCNet card by setting the OWN bit to 1. */ - CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index]; + +// CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index]; + CPCNetDescriptorEntry *entry = &pcnet.rx_de_buffer[de_index * sizeof(CPCNetDescriptorEntry)]; Bts(&entry->status1, PCNET_DESCRIPTORf_OWN); } @@ -498,18 +572,19 @@ interrupt U0 PCNetIRQ() I64 de_index; U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); - //"Interrupt Reason: %X , %b\n",csr,csr; +// "Interrupt Reason: %X , %b\n",csr,csr;Debug; CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer; while (PCNetDriverOwns(&entry[pcnet.current_rx_de_index])) { - "%X", pcnet.current_rx_de_index; + ZenithLog("PCNET IRQ: Saw owned RX DE index %d.\n", pcnet.current_rx_de_index); + de_index = PCNetReceivePacket(&packet_buffer, &packet_length); if (de_index >= 0) // necessary? check increment logic in PCNetReceivePacket. { - ZenithErr("Pushing copy into Net Queue, Releasing Receive Packet"); + ZenithLog("PCNET IRQ: Pushing copy into Net Queue, Releasing Receive Packet\n"); NetQueuePushCopy(packet_buffer, packet_length); PCNetReleaseReceivePacket(de_index); } @@ -524,8 +599,8 @@ interrupt U0 PCNetIRQ() U0 PCIRerouteInterrupts(I64 base) { // todo: comments explaining process, maybe better var names - I64 i; - U8 *da = dev.uncached_alias + IOAPIC_REG; + I64 i; + U8 *da = dev.uncached_alias + IOAPIC_REG; U32 *_d = dev.uncached_alias + IOAPIC_DATA; for (i = 0; i < 4; i++) @@ -567,6 +642,13 @@ U0 PCNetInit() PCNetEnter32BitMode; + U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); + ZenithLog("PCNET INIT START: what is INIT ?: %d\n", Bt(&csr, PCNET_CTRL_INIT)); + ZenithLog("PCNET INIT START: what is STRT ?: %d\n", Bt(&csr, PCNET_CTRL_STRT)); + ZenithLog("PCNET INIT START: what is STOP ?: %d\n", Bt(&csr, PCNET_CTRL_STOP)); + ZenithLog("PCNET INIT START: what is RINT ?: %d\n", Bt(&csr, PCNET_CTRL_RINT)); + + PCNetSetSWStyle; PCNetGetMAC; @@ -574,26 +656,49 @@ U0 PCNetInit() PCNetAllocateBuffers; - PCNetDirectInit; +// PCNetDirectInit; + U8 *setup = PCNetInitBlockSetup(); PCNetSetInterruptCSR; PCNetEnableTXAutoPad; + PCNetWriteCSR(0, PCNetReadCSR(0) | 1 | (1<<6)); +// Bt(&(csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS)), 8); + csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); + ZenithLog("PCNET INIT UPLOAD: what is INIT ?: %d\n", Bt(&csr, PCNET_CTRL_INIT)); + ZenithLog("PCNET INIT UPLOAD: what is STRT ?: %d\n", Bt(&csr, PCNET_CTRL_STRT)); + ZenithLog("PCNET INIT UPLOAD: what is STOP ?: %d\n", Bt(&csr, PCNET_CTRL_STOP)); + ZenithLog("PCNET INIT UPLOAD: what is RINT ?: %d\n", Bt(&csr, PCNET_CTRL_RINT)); + + while (!(PCNetReadCSR(0) & (1<<8))) + Yield; + PCNetExitConfigMode; PCNetSetupInterrupts; Sleep(100);//? necessary? - ClassRep(&pcnet); +/* ClassRep(&pcnet); "pcnet->rx_de_buffer: %X\n", pcnet.rx_de_buffer; "pcnet->tx_de_buffer: %X\n", pcnet.tx_de_buffer; "pcnet->rx_de_buffer_phys: %X\n", pcnet.rx_de_buffer_phys; "pcnet->rx_de_buffer_phys: %X\n", pcnet.tx_de_buffer_phys; +*/ + csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); + ZenithLog("PCNET INIT END: what is INIT ?: %d\n", Bt(&csr, PCNET_CTRL_INIT)); + ZenithLog("PCNET INIT END: what is STRT ?: %d\n", Bt(&csr, PCNET_CTRL_STRT)); + ZenithLog("PCNET INIT END: what is STOP ?: %d\n", Bt(&csr, PCNET_CTRL_STOP)); + ZenithLog("PCNET INIT END: what is RINT ?: %d\n", Bt(&csr, PCNET_CTRL_RINT)); + ZenithLog("PCNET INIT END: what is TXON ?: %d\n", Bt(&csr, 4)); + ZenithLog("PCNET INIT END: what is RXON ?: %d\n", Bt(&csr, 5)); + csr = PCNetReadCSR(PCNET_CSR_POLLINT); + ZenithLog("PCNET INIT END: what is POLLINT ?: %d\n", Bt(&csr, PCNET_CTRL_RINT)); + Free(setup); } I64 EthernetFrameAllocate(U8 **packet_buffer_out, @@ -613,20 +718,23 @@ I64 EthernetFrameAllocate(U8 **packet_buffer_out, //need to see if 3 years later VirtualBox supports APAD_XMT! if (packet_length < ETHERNET_MIN_FRAME_SIZE) + { + ZenithWarn("ETHERNET FRAME ALLOCATE: PCNET APAD XMT TRUNCATE ? ...\n"); packet_length = ETHERNET_MIN_FRAME_SIZE; + } de_index = PCNetAllocateTransmitPacket(ðernet_frame, ETHERNET_MAC_HEADER_LENGTH + packet_length); if (de_index < 0) { - ZenithErr("Ethernet Frame Allocate failure"); + ZenithErr("ETHERNET FRAME ALLOCATE: Failure\n"); return -1; // Positive value expected. Functions calling this must factor this in. } MemCopy(ethernet_frame, destination_address, MAC_ADDRESS_LENGTH); MemCopy(ethernet_frame + MAC_ADDRESS_LENGTH, source_address, MAC_ADDRESS_LENGTH); - ethernet_frame[ETHERNET_ETHERTYPE_OFFSET] = ethertype << 8; + ethernet_frame[ETHERNET_ETHERTYPE_OFFSET] = ethertype >> 8; // << or >> ? Shrine has >> ethernet_frame[ETHERNET_ETHERTYPE_OFFSET + 1] = ethertype & 0xFF; *packet_buffer_out = ethernet_frame + ETHERNET_MAC_HEADER_LENGTH; @@ -639,5 +747,5 @@ U8 *EthernetGetMAC() return pcnet.mac_address; } -PCNetInit; +PCNetInit; \ No newline at end of file diff --git a/src/Home/Net/Sockets.CC b/src/Home/Net/Sockets.CC index 64259c90..fb3978f0 100755 --- a/src/Home/Net/Sockets.CC +++ b/src/Home/Net/Sockets.CC @@ -35,6 +35,8 @@ #define AF_INET 2 #define AF_INET6 10 +#define INADDR_ANY 0 + #define INET_ADDRSTRLEN 16 //pubs.opengroup.com netinit/in.h #define INET6_ADDRSTRLEN 46 @@ -70,7 +72,8 @@ class CIPAddressStorage class CSocketAddressIPV4 { - I16 family; // 'AF_INET' +// I16 family; // 'AF_INET' + U16 family; // 'AF_INET' U16 port; // 'in Network Byte order' ... Big Endian CIPV4Address address; U8 zeroes[8]; // 'same size as socket address' @@ -130,6 +133,22 @@ U0 AddressInfoCopy(CAddressInfo *out, CAddressInfo *in) } } +U0 AddressInfoFree(CAddressInfo *info) +{ + CAddressInfo *next; + + while (info) + { + next = info->next; + + Free(info->address); + Free(info->canonical_name); + Free(info); + + info = next; + } +} + Bool IPV4AddressParse(U8 *string, U32 *destination) { // U8* lexable_string; @@ -159,12 +178,12 @@ Bool IPV4AddressParse(U8 *string, U32 *destination) case TK_I64: if (cc->cur_i64 > 255 || cc->cur_i64 < 0) { - ZenithErr("Invalid value, must be 0 - 255.\n"); + ZenithErr("IPV4 ADDRESS PARSE: Invalid value, must be 0 - 255.\n"); return FALSE; } if (current_section > 3) { - ZenithErr("IP Address can only have 4 sections.\n"); + ZenithErr("IPV4 ADDRESS PARSE: IP Address can only have 4 sections.\n"); return FALSE; } @@ -176,7 +195,7 @@ Bool IPV4AddressParse(U8 *string, U32 *destination) break; default: - ZenithErr("Expected decimal. \n"); + ZenithErr("IPV4 ADDRESS PARSE: Expected decimal. \n"); return FALSE; } break; @@ -189,7 +208,7 @@ Bool IPV4AddressParse(U8 *string, U32 *destination) break; default: - ZenithErr("Expected dot. \n"); + ZenithErr("IPV4 ADDRESS PARSE: Expected dot. \n"); return FALSE; } break; @@ -275,11 +294,17 @@ U8 *NetworkToPresentation(I64 address_family, CIPAddressStorage *source) ipv4_source = source; - StrPrint(ip_string, "%d.%d.%d.%d", +/* StrPrint(ip_string, "%d.%d.%d.%d", ipv4_source->address.u8[3], ipv4_source->address.u8[2], ipv4_source->address.u8[1], - ipv4_source->address.u8[0]); + ipv4_source->address.u8[0]);*/ + + StrPrint(ip_string, "%d.%d.%d.%d", + ipv4_source->address.u8[0], + ipv4_source->address.u8[1], + ipv4_source->address.u8[2], + ipv4_source->address.u8[3]); break; case AF_INET6: diff --git a/src/Home/Net/Tests/DHCPTest1.CC b/src/Home/Net/Tests/DHCPTest1.CC new file mode 100755 index 00000000..9d649f92 --- /dev/null +++ b/src/Home/Net/Tests/DHCPTest1.CC @@ -0,0 +1,4 @@ +#include "C:/Home/Net/DHCP" +#include "C:/Home/Net/NetHandlerTask" + +NetConfigure; \ No newline at end of file diff --git a/src/Home/Net/Tests/DNSTest1.CC b/src/Home/Net/Tests/DNSTest1.CC new file mode 100755 index 00000000..662e3fe9 --- /dev/null +++ b/src/Home/Net/Tests/DNSTest1.CC @@ -0,0 +1,16 @@ + +#include "../DNS" +#include "../NetHandlerTask" + +/* +"Manually setting DNS Resolver IP.\n"; + +CIPV4Address *addr = CAlloc(sizeof(CIPV4Address)); +PresentationToNetwork(AF_INET, "192.168.1.254", addr); + +DNSSetResolverIPV4(addr->address); +*/ +"Trying Host() at \"google.com\".\n"; +Host("google.com"); + +Free(addr); \ No newline at end of file diff --git a/src/Home/Net/Tests/MakeBreakDown.CC b/src/Home/Net/Tests/MakeBreakDown.CC new file mode 100755 index 00000000..71b07a73 --- /dev/null +++ b/src/Home/Net/Tests/MakeBreakDown.CC @@ -0,0 +1,33 @@ +#include "C:/Home/Net/Net.HH" + +#include "C:/Home/Net/NetQueue" +#include "C:/Home/Net/PCNet" +#include "C:/Home/Net/Ethernet" + +Sleep(300); + +#include "C:/Home/Net/ARP" +#include "C:/Home/Net/IPV4" +#include "C:/Home/Net/ICMP" + +#include "C:/Home/Net/Sockets" + +#include "C:/Home/Net/UDP" + +#include "C:/Home/Net/DNS" +#include "C:/Home/Net/DHCP" + + +Sleep(300); + +#include "C:/Home/Net/NetHandlerTask" // needs IPV4, UDP, ICMP + +NetConfigure; + +//ClassRep(&pcnet); +Sleep(1000); + +XTalk(Fs, "Host(\"google.com\");\n"); + +Dir; + diff --git a/src/Home/Net/Tests/UDPSendTrash.CC b/src/Home/Net/Tests/UDPSendTrash.CC new file mode 100755 index 00000000..2b70cbbe --- /dev/null +++ b/src/Home/Net/Tests/UDPSendTrash.CC @@ -0,0 +1,21 @@ +CAddressInfo *result = NULL; +I64 error = DNSGetAddressInfo("zenithos.org", NULL, &result); +I64 i = 0; + +if (error < 0) +{ + ZenithErr("failed at DNS Get Address Info.\n"); +} +else +{ + CUDPSocket *u = UDPSocket(AF_INET); + CSocketAddressIPV4 *ipv4_addr = result->address; + + ipv4_addr->port = EndianU16(80); + U8 *b = CAlloc(4); + b[0] = 0xDE; + b[1] = 0xAD; + b[2] = 0xBE; + b[3] = 0xEF; + UDPSocketSendTo(u, b, 4, ipv4_addr); +} diff --git a/src/Home/Net/UDP.CC b/src/Home/Net/UDP.CC index e60eafac..91a38fe7 100755 --- a/src/Home/Net/UDP.CC +++ b/src/Home/Net/UDP.CC @@ -1,6 +1,6 @@ //#include "IPV4" -#include "ICMP" // this is wrong and only doing this because we're just in dev right now. probably need approach like Shrine, MakeNet, idk. -#include "Sockets" +//#include "ICMP" // this is wrong and only doing this because we're just in dev right now. probably need approach like Shrine, MakeNet, idk. +//#include "Sockets" #define UDP_MAX_PORT 65535 @@ -21,6 +21,9 @@ class CUDPSocket I64 receive_len; CSocketAddressStorage receive_address; // based on ->family, cast or assign to a var as IPV4/IPV6 CSocketAddress U16 bound_to; // represents the currently bound port + + CSocketAddressStorage from_address; // when UDP Handler sees UDP packet, this is filled with where the packet came from. + // recvfrom uses this to fill its address_out parameter. }; /*************************************************** @@ -236,35 +239,36 @@ CUDPTreeQueue *UDPTreeNodeQueueSocketFind(CUDPSocket *socket, CUDPTreeNode *node } CUDPTreeQueue *UDPTreeNodeQueueIPV4Find(U32 address, CUDPTreeNode *node) -{ // address should be pulled from an instance of CIPV4Address (TODO... double check what bit order we're in ?) +{ // address should be pulled from an instance of CIPV4Address (TODO... double check what bit order we're in ?) + // TODO: should INADDR_ANY entries be stored and looped, or keep current returning ASAP at INNADDR_ANY ? - CUDPTreeQueue *temp_queue; - CSocketAddressIPV4 *temp_ip; + CUDPTreeQueue *temp_queue = node->queue; + CSocketAddressIPV4 *temp_ip; - if (node->queue) + if (temp_queue) { - if (node->queue->socket->receive_address.family == AF_INET) - { - temp_ip = &node->queue->socket->receive_address; - if (temp_ip->address == address) - return node->queue; - } - - temp_queue = node->queue->next; - while (temp_queue != node->queue) + do { if (temp_queue->socket->receive_address.family == AF_INET) { temp_ip = &temp_queue->socket->receive_address; - if (temp_ip->address == address) + ZenithLog("UDPTreeNodeQueueIPV4Find: addr, nodequeue addr: %08X, %08X\n", + address, temp_ip->address.address); + + if (temp_ip->address.address == address || temp_ip->address.address == INADDR_ANY) + { + ZenithLog("UDPTreeNodeQueueIPV4Find: Address match: addr, nodequeue: %08X, %08X \n", + address, temp_ip->address.address); return temp_queue; + } } temp_queue = temp_queue->next; } + while (temp_queue != node->queue); } - return NULL; + return NULL; } CUDPTreeQueue *UDPTreeNodeQueueSocketSinglePop(CUDPSocket *socket, CUDPTreeNode *node) @@ -342,7 +346,7 @@ I64 UDPPacketAllocate(U8 **frame_out, sizeof(CUDPHeader) + length); if (de_index < 0) { - ZenithLog("UDP Ethernet Frame Allocate failed.\n"); + ZenithLog("UDP PACKET ALLOCATE: Ethernet Frame Allocate failed.\n"); return de_index; } @@ -353,8 +357,11 @@ I64 UDPPacketAllocate(U8 **frame_out, header->length = EndianU16(sizeof(CUDPHeader) + length); header->checksum = 0; +// ClassRep(header); + *frame_out = ethernet_frame + sizeof(CUDPHeader); + return de_index; } U0 UDPPacketFinish(I64 de_index) @@ -414,13 +421,13 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) break; default: - ZenithErr("Unsuccessful UDP Socket Bind: Socket state-machine must be in READY state.\n"); + ZenithErr("UDP SOCKET BIND: Failed, Socket state-machine must be in READY state.\n"); return -1; } if (udp_socket->bound_to) { - ZenithErr("Attempted UDP Socket Bind while UDP socket currently bound."); + ZenithErr("UDP SOCKET BIND: UDP Socket currently Bound.\n"); return -1; } @@ -430,7 +437,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) if (udp_socket->receive_address.family == AF_INET6) { - ZenithErr("Attempted UDP Socket Bind with incompatible Address type.\n"); + ZenithErr("UDP SOCKET BIND: Incompatible Address type.\n"); return -1; } @@ -448,7 +455,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) if (udp_socket->receive_address.family == AF_INET) { - ZenithErr("Attempted UDP Socket Bind with incompatible Address type.\n"); + ZenithErr("UDP SOCKET BIND: Incompatible Address type.\n"); return -1; } @@ -464,7 +471,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) break; case AF_UNSPEC: - Debug("TODO: AF_UNSPEC UDP BIND"); + Debug("TODO: AF_UNSPEC UDP BIND -- param family"); break; } @@ -481,9 +488,10 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) switch (address_source->family) { case AF_INET: + // TODO: will any INADDR_ANY sockets bound at the port break this? if (UDPTreeNodeQueueIPV4Find(ipv4_receive->address.address, temp_node)) { - ZenithErr("Attempted UDP Socket Bind at an address already in Bound Socket Tree !\n"); + ZenithErr("UDP SOCKET BIND: Address already in Bound Socket Tree !\n"); return -1; } else @@ -496,7 +504,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) break; case AF_UNSPEC: - Debug("TODO: AF_UNSPEC UDP BIND"); + Debug("TODO: AF_UNSPEC UDP BIND -- found in bound tree"); break; } } @@ -524,7 +532,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source) break; default: - ZenithErr("Unsuccessful UDP Socket Bind: Misconfigured Socket state-machine.\n"); + ZenithErr("UDP SOCKET BIND: Failed, Misconfigured Socket state-machine.\n"); return -1; } @@ -585,7 +593,7 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd break; default: - ZenithErr("Unsuccessful UDP Socket Receive From: Socket state-machine must be in OPEN or BOUND state.\n"); + ZenithErr("UDP SOCKET RECEIVE FROM: Socket state-machine must be in OPEN or BOUND state.\n"); return -1; } @@ -595,11 +603,14 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd if (udp_socket->receive_timeout_ms != 0) udp_socket->receive_max_timeout = counts.jiffies + udp_socket->receive_timeout_ms * JIFFY_FREQ / 1000; +// ClassRep(udp_socket); + ZenithLog("UDP SOCKET RECEIVE FROM: udp_socket->receive_buffer: 0x%0X.\n", udp_socket->receive_buffer); while (udp_socket->receive_buffer != NULL) { // 'Check for timeout' if (udp_socket->receive_timeout_ms != 0 && counts.jiffies > udp_socket->receive_max_timeout) { // Shrine has TODO: 'seterror(EWOULDBLOCK)' investigate this udp_socket->receive_len = -1; // ? + ZenithErr("UDP SOCKET RECEIVE FROM: Timed out.\n"); break; } @@ -608,15 +619,18 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd if (address_out) { - switch (udp_socket->receive_address.family) +// switch (udp_socket->receive_address.family) + switch (udp_socket->from_address.family) { case AF_INET: ipv4_socket_addr = address_out; - MemCopy(ipv4_socket_addr, &udp_socket->receive_address, sizeof(CSocketAddressIPV4)); +// MemCopy(ipv4_socket_addr, &udp_socket->receive_address, sizeof(CSocketAddressIPV4)); + MemCopy(ipv4_socket_addr, &udp_socket->from_address, sizeof(CSocketAddressIPV4)); break; case AF_INET6: ipv6_socket_addr = address_out; - MemCopy(ipv6_socket_addr, &udp_socket->receive_address, sizeof(CSocketAddressIPV6)); +// MemCopy(ipv6_socket_addr, &udp_socket->receive_address, sizeof(CSocketAddressIPV6)); + MemCopy(ipv6_socket_addr, &udp_socket->from_address, sizeof(CSocketAddressIPV6)); break; case AF_UNSPEC: Debug("TODO: UDP Receive From Error AF_UNSPEC UDPSocket Address Family\n"); @@ -645,13 +659,13 @@ I64 UDPSocketSendTo(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAddressS break; // and use stored address as send address. case SOCKET_STATE_READY: // If socket state is initial, attempt to bind it to destination. - ZenithLog("UDP Socket Send To but Socket unbound. Attempting Bind at address parameter.\n"); + ZenithLog("UDP SOCKET SEND TO: Socket unbound. Attempting Bind at address parameter.\n"); UDPSocketBind(udp_socket, destination_addr); dest = destination_addr; break; default: - ZenithErr("Unsuccessful UDP Socket Receive From: Socket state-machine must be in OPEN, BOUND or READY state.\n"); + ZenithErr("UDP SOCKET SEND TO: Socket state-machine must be in OPEN, BOUND or READY state.\n"); return -1; } @@ -689,21 +703,29 @@ I64 UDPSocketSendTo(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAddressS I64 UDPHandler(CIPV4Packet *packet) { // TODO: Need either two UDP handlers for IPv4/IPv6, or logic changes if IPV6 is desired. - U16 source_port; - U16 destination_port; - U8 *data; - I64 length; - CUDPTreeNode *node; - CUDPTreeQueue *queue; - CUDPSocket *udp_socket; - CSocketAddressIPV4 *ipv4_addr; - I64 num_receive; + U16 source_port; + U16 destination_port; + U8 *data; + I64 length; + CUDPTreeNode *node; + CUDPTreeQueue *queue; + CUDPSocket *udp_socket; + CSocketAddressIPV4 *ipv4_addr; + I64 num_receive; + + ZenithLog("UDP HANDLER: Beginning handling UDP Packet.\n"); +/* ZenithWarn("UDP HANDLER: Yielding for a little bit as a debug.\n"); + ZenithWarn("UDP HANDLER: ...\n"); + I64 c = counts.jiffies; + while (counts.jiffies < c + 1000) + Yield; + ZenithWarn("UDP HANDLER: ...\n");*/ I64 error = UDPParsePacket(&source_port, &destination_port, &data, &length, packet); if (error < 0) { - ZenithErr("UDP Handler Packet Parse Error.\n"); + ZenithErr("UDP HANDLER: Packet Parse Error.\n"); return error; } @@ -712,41 +734,44 @@ I64 UDPHandler(CIPV4Packet *packet) node = UDPTreeNodeFind(destination_port, udp_globals.bound_socket_tree); if (node) { - // TODO: implement check for INADDR_ANY in socket queue queue = UDPTreeNodeQueueIPV4Find(packet->destination_ip_address, node); // TODO: make sure bit order is correct here!! if (queue) { udp_socket = queue->socket; - ZenithLog("Handled UDP packet, port and address are in bound tree.\n"); + ZenithLog("UDP HANDLER: Port and Address are in bound tree.\n"); } else { - ZenithWarn("Handled UDP packet, found node for port, but address is not in node queue.\n"); + ZenithWarn("UDP HANDLER: Found node for port, but address is not in node queue.\n"); + ZenithWarn(" UDP packet dest ip: 0x%0X.\n", packet->destination_ip_address); return -1; } } else { - ZenithWarn("Handled UDP packet but node for port is not in tree.\n"); + ZenithWarn("UDP HANDLER: Node for Port is not in tree.\n"); return -1; } } else { - ZenithWarn("Handled UDP packet but socket tree is currently empty.\n"); + ZenithWarn("UDP HANDLER: Socket tree is currently empty.\n"); return -1; } + ZenithLog("UDP HANDLER: Checking if UDP Socket's Receive-Buffer exists. UDPSocket at: 0x%0X \n", udp_socket); + ZenithLog(" It probably exists, wtf going on ? udp_socket->receive_buffer: 0x%0X.\n", udp_socket->receive_buffer); // at this point, udp_socket is set, otherwise has already returned -1. - if (udp_socket->receive_buffer) { + ZenithLog("UDP HANDLER: Saw UDP Socket receive buffer exists, about to copy data into it.\n"); num_receive = udp_socket->receive_len; if (num_receive > length) { + ZenithWarn("UDP HANDLER: Truncating UDP socket receive length. num_receive , len : %d, %d\n", + num_receive, length); num_receive = length; - ZenithWarn("UDP Handler: Truncating UDP socket receive length.\n"); } MemCopy(udp_socket->receive_buffer, data, num_receive); @@ -759,10 +784,13 @@ I64 UDPHandler(CIPV4Packet *packet) udp_socket->receive_buffer = NULL; udp_socket->receive_len = num_receive; - ipv4_addr = &udp_socket->receive_address; +// ipv4_addr = &udp_socket->receive_address; + ipv4_addr = &udp_socket->from_address; + ipv4_addr->family = AF_INET; ipv4_addr->port = EndianU16(source_port); ipv4_addr->address.address = EndianU32(packet->source_ip_address); + ZenithLog("UDP HANDLER: Copying packet source IP (BE) to FROM_ADDRESS of UDP Socket: %08X \n", ipv4_addr->address.address); } return error;