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
This commit is contained in:
TomAwezome 2020-08-07 02:39:07 -04:00
parent 31d3760e34
commit 20484c6ada
19 changed files with 1227 additions and 164 deletions

View file

@ -1,5 +1,5 @@
#include "PCNet" //#include "PCNet"
#include "Ethernet" //#include "Ethernet"
#define ARP_HASHTABLE_SIZE 1024 #define ARP_HASHTABLE_SIZE 1024
@ -54,8 +54,9 @@ I64 ARPSend(U16 operation,
U32 target_ip) U32 target_ip)
{//method currently assumes send_ and target_ip EndianU16 already... {//method currently assumes send_ and target_ip EndianU16 already...
U8 *ethernet_frame; U8 *ethernet_frame;
CARPHeader *header; CARPHeader *header;
I64 de_index = EthernetFrameAllocate(&ethernet_frame, I64 de_index = EthernetFrameAllocate(&ethernet_frame,
send_mac_address, send_mac_address,
dest_mac_address, dest_mac_address,
@ -85,10 +86,14 @@ I64 ARPSend(U16 operation,
CARPHash *ARPCacheFindByIP(U32 ip_address) CARPHash *ARPCacheFindByIP(U32 ip_address)
{ {
U8 *ip_string = MStrPrint("%d", ip_address); U8 *ip_string = MStrPrint("%X", ip_address);
CARPHash *entry = HashFind(ip_string, arp_cache, HTT_ARP); CARPHash *entry = HashFind(ip_string, arp_cache, HTT_ARP);
if (entry == NULL) 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); Free(ip_string);
return entry; return entry;
@ -96,19 +101,24 @@ CARPHash *ARPCacheFindByIP(U32 ip_address)
CARPHash *ARPCachePut(U32 ip_address, U8 *mac_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); CARPHash *entry = ARPCacheFindByIP(ip_address);
//Free(entry); // something seems wrong about this... //Free(entry); // something seems wrong about this...
if (!entry) if (!entry)
{ {
entry = CAlloc(sizeof(CARPHash)); 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); MemCopy(entry->mac_address, mac_address, 6);
HashAdd(entry, arp_cache); HashAdd(entry, arp_cache);
} }
else 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; return entry;
} }
@ -139,16 +149,18 @@ U0 ARPSetIPV4Address(U32 ip_address)
//the NetQueueHandler //the NetQueueHandler
I64 ARPHandler(CEthernetFrame *ethernet_frame) 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 // 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 .. // since revising Shrine implement, will do same checks for now ..
if (ethernet_frame->ethertype != ETHERTYPE_ARP) 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 return -1; // External use of ARPHandler must account for -1 error codes
} }
if (ethernet_frame->length < sizeof(CARPHeader)) 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 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 (?) // hlen(?) != 6(?), and that plen(?) == 4 (?)
if (EndianU16(header->hardware_type) != HTYPE_ETHERNET) 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 return -1; // External use of ARPHandler must account for -1 error codes
} }
if (EndianU16(header->protocol_type) != ETHERTYPE_IPV4) 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 return -1; // External use of ARPHandler must account for -1 error codes
} }
if (header->hardware_addr_len != HLEN_ETHERNET) 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 return -1; // External use of ARPHandler must account for -1 error codes
} }
if (header->protocol_addr_len != PLEN_IPV4) 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 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; ARPCacheInit;

534
src/Home/Net/DHCP.CC Executable file
View file

@ -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(&ethernet_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(&ethernet_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");
}

View file

@ -1,4 +1,4 @@
#include "UDP"; //#include "UDP";
// https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf // https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf
// https://en.wikipedia.org/wiki/Domain_Name_System // https://en.wikipedia.org/wiki/Domain_Name_System
@ -17,6 +17,9 @@
#define DNS_CLASS_IN 1 #define DNS_CLASS_IN 1
#define DNS_TIMEOUT 5000 #define DNS_TIMEOUT 5000
#define DNS_MAX_RETRIES 5 // Shrine has 3, why not 5? :^)
class CDNSHash:CHash class CDNSHash:CHash
{ // store U8 *hostname as CHash->str U8 * { // store U8 *hostname as CHash->str U8 *
CAddressInfo info; CAddressInfo info;
@ -82,25 +85,30 @@ CDNSHash *DNSCacheFind(U8 *hostname)
CDNSHash *entry = HashFind(hostname, dns_cache, HTT_DNS); CDNSHash *entry = HashFind(hostname, dns_cache, HTT_DNS);
if (entry == NULL) 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; return entry;
} }
CDNSHash *DNSCachePut(U8 *hostname, CAddressInfo *info) 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); CDNSHash *entry = DNSCacheFind(hostname);
if (!entry) if (!entry)
{ {
entry = CAlloc(sizeof(CDNSHash)); entry = CAlloc(sizeof(CDNSHash));
entry->str = StrNew(hostname); entry->str = StrNew(hostname);
entry->type = HTT_DNS;
AddressInfoCopy(&entry->info, info); AddressInfoCopy(&entry->info, info);
HashAdd(entry, dns_cache); HashAdd(entry, dns_cache);
} }
else 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; return entry;
} }
@ -150,17 +158,21 @@ I64 DNSSendQuestion(U16 id, U16 local_port, CDNSQuestion *q)
switch (dns_globals.addr_family) switch (dns_globals.addr_family)
{ {
case AF_UNSPEC: // 0, global dns ip not set case AF_UNSPEC: // 0, global dns ip not set
ZenithErr("DNS SEND QUESTION: Failed, global dns addr family was AF_UNSPEC.\n");
return -1; return -1;
case AF_INET6: 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'); throw('DNS');
case AF_INET: case AF_INET:
ipv4_addr = &dns_globals.dns_ip; ipv4_addr = &dns_globals.dns_ip;
if (!*ipv4_addr) if (!*ipv4_addr)
{
ZenithErr("DNS SEND QUESTION: Failed, ipv4_addr had no value set.\n");
return -1; return -1;
}
} }
// UDPPacketAllocate currently only accepts IPV4 ... // UDPPacketAllocate currently only accepts IPV4 ...
@ -171,7 +183,10 @@ I64 DNSSendQuestion(U16 id, U16 local_port, CDNSQuestion *q)
53, 53,
sizeof(CDNSHeader) + DNSCalculateQuestionSize(q)); sizeof(CDNSHeader) + DNSCalculateQuestionSize(q));
if (de_index < 0) if (de_index < 0)
{
ZenithErr("DNS SEND QUESTION: Failed, UDPPacketAllocate returned error.\n");
return de_index; return de_index;
}
flags = (DNS_OP_QUERY << 11) | DNS_FLAG_RD; 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) 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; return -1;
} }
@ -228,7 +243,7 @@ I64 DNSParseDomainName(U8 *packet_data, I64 packet_length, U8 **data_inout, I64
*data_inout = data + 1; *data_inout = data + 1;
*length_inout = length - 1; *length_inout = length - 1;
jump_taken = TRUE; 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); 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; 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; CDNSHeader *header;
CDNSQuestion *question; CDNSQuestion *question;
@ -328,7 +343,7 @@ I64 DNSParseResponse(U16 id, U8 *data, I64 len, CDNSHeader **header_out, CDNSQue
if (length < sizeof(CDNSHeader)) if (length < sizeof(CDNSHeader))
{ {
ZenithErr("DNS Response Parsed, length too short.\n"); ZenithErr("DNS PARSE RESPONSE: Length too short.\n");
return -1; 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) 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; return -1;
} }
@ -399,7 +414,7 @@ U0 DNSFreeQuestion(CDNSQuestion *q)
Free(q->q_name.labels[0]); Free(q->q_name.labels[0]);
} }
U0 DNSFreeRR(CDNSRR *r) U0 DNSFreeRR(CDNSRR *rr)
{ {
Free(rr->name.labels[0]); 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) 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 retries = 0;
I64 timeout = DNS_TIMEOUT; 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; U16 id = RandU16;
I64 error = 0; I64 error = 0;
U8 *buffer; U8 buffer[2048];
I64 count; I64 count;
Bool have; Bool have; // ??
CDNSQuestion q; CDNSQuestion q;
CDNSHeader *header; CDNSHeader *header;
@ -450,24 +466,214 @@ I64 DNSRunQuery(CUDPSocket *udp_socket, U8 *name, U16 port, CAddressInfo **resul
CSocketAddressIPV4 ipv4_addr; CSocketAddressIPV4 ipv4_addr;
CSocketAddressIPV4 ipv4_addr_in; // ? CSocketAddressIPV4 ipv4_addr_in; // ?
CSocketAddressIPV4 *ipv4_addr_temp;
CAddressInfo *res; CAddressInfo *res;
//setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO_MS, &timeout, sizeof(timeout)) //setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO_MS, &timeout, sizeof(timeout))
udp_socket->receive_timeout_ms = 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;
} }
*/
/* // Shrine has port arg as U8 *service with a no_warn and says it should be parsed as port, allowing that here
I64 DNSRunQuery(socket?, U8 *name, U16 port, CAddressInfo **result_out) // 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) 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, &current->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() U0 DNSInit()

View file

@ -36,6 +36,8 @@ U0 EthernetFrameParse(CEthernetFrame *frame_out, U8 *frame, U16 length)
//of the current system should be done with less extra allocation //of the current system should be done with less extra allocation
//altogether, more passing. //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->destination_address, frame, MAC_ADDRESS_LENGTH);
MemCopy(frame_out->source_address, frame + MAC_ADDRESS_LENGTH, 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->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; EthernetInitGlobals;

View file

@ -1,4 +1,4 @@
#include "IPV4" //#include "IPV4"
#define ICMP_TYPE_ECHO_REPLY 0 #define ICMP_TYPE_ECHO_REPLY 0
#define ICMP_TYPE_ECHO_REQUEST 8 #define ICMP_TYPE_ECHO_REQUEST 8
@ -32,7 +32,7 @@ I64 ICMPSendReply(U32 destination_ip_address,
sizeof(CICMPHeader) + length); sizeof(CICMPHeader) + length);
if (de_index < 0) 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; return de_index;
} }
@ -57,7 +57,7 @@ I64 ICMPHandler(CIPV4Packet *packet)
if (packet->length < sizeof(CICMPHeader)) if (packet->length < sizeof(CICMPHeader))
{ {
ZenithLog("ICMP Handler caught wrong IPV4 length.\n"); ZenithErr("ICMP HANDLER: Caught wrong IPV4 length.\n");
return -1; return -1;
} }

View file

@ -1,4 +1,4 @@
#include "ARP" //#include "ARP"
#define IPV4_ERR_ADDR_INVALID -200001 #define IPV4_ERR_ADDR_INVALID -200001
#define IPV4_ERR_HOST_UNREACHABLE -200002 #define IPV4_ERR_HOST_UNREACHABLE -200002
@ -42,7 +42,7 @@ class CIPV4Header
U32 source_ip_address; U32 source_ip_address;
U32 destination_ip_address; U32 destination_ip_address;
} };
class CIPV4Globals class CIPV4Globals
{ // _be indicates Big Endian { // _be indicates Big Endian
@ -60,7 +60,7 @@ U0 InitIPV4Globals()
ipv4_globals.local_ip_be = 0; ipv4_globals.local_ip_be = 0;
ipv4_globals.ipv4_router_address = 0; ipv4_globals.ipv4_router_address = 0;
ipv4_globals.ipv4_subnet_mask = 0; ipv4_globals.ipv4_subnet_mask = 0;
} };
// For now, trusting Shrine's implement // For now, trusting Shrine's implement
// of checksum. Shrine links back to // of checksum. Shrine links back to
@ -96,25 +96,26 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out)
CARPHash *entry; CARPHash *entry;
I64 retries; I64 retries;
I64 attempt; 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) 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; return IPV4_ERR_ADDR_INVALID;
} }
if (ip_address == 0xFFFFFFFF) 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; *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; 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)) 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... // 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" else // "local network"
{ {
ZenithLog("GET MAC FOR IP: Attempting ARP Find by IP for address: %d.\n", ip_address);
entry = ARPCacheFindByIP(ip_address); entry = ARPCacheFindByIP(ip_address);
if (entry) if (entry)
@ -138,6 +142,13 @@ I64 GetMACAddressForIP(U32 ip_address, U8 **mac_out)
retries = 4; retries = 4;
while (retries) while (retries)
{ {
ARPSend(ARP_REQUEST,
ethernet_globals.ethernet_broadcast,
EthernetGetMAC,
ipv4_globals.local_ip_be,
ethernet_globals.ethernet_null,
EndianU32(ip_address));
attempt = 0; attempt = 0;
for (attempt = 0; attempt < 50; attempt++) 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 //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; return IPV4_ERR_HOST_UNREACHABLE;
} }
} }
@ -179,7 +190,7 @@ I64 IPV4PacketAllocate(U8 **frame_out,
if (error < 0) 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; return error;
} }
@ -190,7 +201,7 @@ I64 IPV4PacketAllocate(U8 **frame_out,
sizeof(CIPV4Header) + length); sizeof(CIPV4Header) + length);
if (de_index < 0) if (de_index < 0)
{ {
ZenithLog("IPV4 Ethernet Frame Allocate failed.\n"); ZenithLog("IPV4 PACKET ALLOCATE: Ethernet Frame Allocate failed.\n");
return de_index; return de_index;
} }
@ -208,7 +219,7 @@ I64 IPV4PacketAllocate(U8 **frame_out,
header->header_checksum = 0; // why is 0 ok? header->header_checksum = 0; // why is 0 ok?
header->source_ip_address = EndianU32(source_ip_address); header->source_ip_address = EndianU32(source_ip_address);
header->destination_ip_address = EndianU32(destination_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); *frame_out = ethernet_frame + sizeof(CIPV4Header);
return de_index; return de_index;

View file

@ -8,7 +8,7 @@
/* Ethernet Frame Size. /* 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. */ 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 HTYPE_ETHERNET 1
#define HLEN_ETHERNET 6 #define HLEN_ETHERNET 6

View file

@ -9,13 +9,13 @@ U0 IPV4Handler(CEthernetFrame *ethernet_frame)
switch (packet.protocol) switch (packet.protocol)
{ {
case IP_PROTOCOL_ICMP: case IP_PROTOCOL_ICMP:
ZenithLog("IPV4 Handler: ICMP.\n"); ZenithLog("IPV4 HANDLER: ICMP.\n");
ICMPHandler(&packet); ICMPHandler(&packet);
break; break;
case IP_PROTOCOL_TCP: case IP_PROTOCOL_TCP:
break; break;
case IP_PROTOCOL_UDP: case IP_PROTOCOL_UDP:
ZenithLog("IPV4 Handler: UDP.\n"); ZenithLog("IPV4 HANDLER: UDP.\n");
UDPHandler(&packet); UDPHandler(&packet);
break; break;
} }
@ -30,9 +30,11 @@ U0 HandleNetQueueEntry(CNetQueueEntry *entry)
switch (ethernet_frame.ethertype) switch (ethernet_frame.ethertype)
{ {
case ETHERTYPE_ARP: case ETHERTYPE_ARP:
ZenithLog("HANDLE NETQUEUE ENTRY: ARP.\n");
ARPHandler(&ethernet_frame); ARPHandler(&ethernet_frame);
break; break;
case ETHERTYPE_IPV4: case ETHERTYPE_IPV4:
ZenithLog("HANDLE NETQUEUE ENTRY: IPV4.\n");
IPV4Handler(&ethernet_frame); IPV4Handler(&ethernet_frame);
break; break;
} }
@ -42,10 +44,11 @@ U0 NetHandlerTask(I64)
{ {
while (TRUE) while (TRUE)
{ {
CNetQueueEntry *entry = NetQueuePull; CNetQueueEntry *entry = NetQueuePull();
if (entry) if (entry)
{ {
ZenithLog("NET HANDLER TASK: Caught NetQueue Entry, handling.\n");
HandleNetQueueEntry(entry); HandleNetQueueEntry(entry);
} }
else 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",,); net_handler_task = Spawn(&NetHandlerTask, NULL, "NetQueueHandler");

View file

@ -13,6 +13,7 @@ class CNetQueueEntry:CQueue
U8 frame[ETHERNET_FRAME_SIZE]; U8 frame[ETHERNET_FRAME_SIZE];
}; };
/* global variable, holds pointer of Ethernet Queue. /* global variable, holds pointer of Ethernet Queue.
This acts as the Head of the Queue, Entries act This acts as the Head of the Queue, Entries act
as the Tail of the Queue. as the Tail of the Queue.
@ -21,11 +22,14 @@ class CNetQueueEntry:CQueue
CQueue *net_queue; // no QueueRemove the Head! only Entries! CQueue *net_queue; // no QueueRemove the Head! only Entries!
/* Net Handler Task is set idle and active depending /* 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"$ */ on if entries in Net Queue. See $LK,"NetHandlerTask",A="FF:C:/Home/Net/NetHandlerTask.CC,net_handler_task"$ */
CTask *net_handler_task = NULL; CTask *net_handler_task = NULL;
U0 NetQueueInit() U0 NetQueueInit()
{ {
net_queue = CAlloc(sizeof(CQueue)); net_queue = CAlloc(sizeof(CQueue));
@ -35,11 +39,14 @@ U0 NetQueueInit()
CNetQueueEntry *NetQueuePull() CNetQueueEntry *NetQueuePull()
{/* Returns a pointer to a CNetQueueEntry, {/* Returns a pointer to a CNetQueueEntry,
or NULL pointer if Net Queue is empty. */ or NULL pointer if Net Queue is empty. */
CNetQueueEntry *entry; CNetQueueEntry *entry;
if (net_queue->next != net_queue) if (net_queue->next != net_queue)
{ {
entry = net_queue->next; entry = net_queue->next;
ZenithLog("NETQUEUE PULL: Removing entry from queue.\n");
QueueRemove(entry); QueueRemove(entry);
} }
else // Queue is empty if head->next is head itself. 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 into the Net Queue. The NetQueueEntry is inserted
after the last entry of net_queue to keep new after the last entry of net_queue to keep new
items in the back of the Queue, old in front. */ items in the back of the Queue, old in front. */
CNetQueueEntry *entry = CAlloc(sizeof(CNetQueueEntry)); CNetQueueEntry *entry = CAlloc(sizeof(CNetQueueEntry));
entry->length = length; entry->length = length;
MemCopy(entry->frame, data, length); MemCopy(entry->frame, data, length);
QueueInsert(entry, net_queue->last); QueueInsert(entry, net_queue->last);
//Set Net Handler Task active. //Set Net Handler Task active.
ZenithLog("ACTIVE: NetHandler\n"); ZenithLog("NETQUEUE PUSH COPY: Setting NetHandler ACTIVE.\n");
if (net_handler_task) if (net_handler_task)
LBtr(&net_handler_task->task_flags, TASKf_IDLE); LBtr(&net_handler_task->task_flags, TASKf_IDLE);
} }
NetQueueInit; NetQueueInit;

28
src/Home/Net/NetStart.CC Executable file
View file

@ -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");

View file

@ -13,8 +13,8 @@
- Clear documentation. - Clear documentation.
*/ */
#include "Net.HH" //#include "Net.HH"
#include "NetQueue" //#include "NetQueue"
#define PCNET_DEVICE_ID 0x2000 #define PCNET_DEVICE_ID 0x2000
#define PCNET_VENDOR_ID 0x1022 #define PCNET_VENDOR_ID 0x1022
@ -53,7 +53,9 @@
#define PCNET_CSR_RXRINGLEN 76 #define PCNET_CSR_RXRINGLEN 76
#define PCNET_CSR_TXRINGLEN 78 #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. // 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) #define PCNET_INT_BSWP 2 // Byte Swap (Big-Endian / Little-Endian)
@ -110,9 +112,21 @@ class CPCNetDescriptorEntry
U32 reserved; U32 reserved;
}; };
class CPCNetBufferSetup
{
U16 mode;
U8 rlen;
U8 tlen;
U8 mac[6];
U16 reserved;
U8 ladr[8];
U32 rxbuf;
U32 txbuf;
};
CPCIDev *PCNetPCIDevFind() CPCIDev *PCNetPCIDevFind()
{// Find and return PCNetII card as a CPCIDev pointer. {// Find and return PCNetII card as a CPCIDev pointer.
return PCIDevFind(,, PCNET_VENDOR_ID, PCNET_DEVICE_ID); return PCIDevFind(,, PCNET_VENDOR_ID, PCNET_DEVICE_ID);
} }
@ -121,6 +135,7 @@ U32 PCNetGetIOBase()
of PCNet card. Bits 0-4 are not of PCNet card. Bits 0-4 are not
for the IO base, so an AND with for the IO base, so an AND with
~0x1F ignores those bits. */ ~0x1F ignores those bits. */
U32 io_base = pcnet.pci->base[0] & ~0x1F; U32 io_base = pcnet.pci->base[0] & ~0x1F;
return io_base; return io_base;
} }
@ -129,8 +144,9 @@ U0 PCNetReset()
{/* Reads the 32- and 16-bit RESET registers, {/* Reads the 32- and 16-bit RESET registers,
which, regardless of which mode the card is in, which, regardless of which mode the card is in,
will reset it back to 16-bit mode. */ 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 Busy(5); // OSDev says minimum 1 æS
} }
@ -139,8 +155,8 @@ U0 PCNetEnter32BitMode()
Summary: A 32-bit write (while in 16-bit mode) Summary: A 32-bit write (while in 16-bit mode)
to RDP will cause 16-bit mode exit to RDP will cause 16-bit mode exit
and immediate enter into 32-bit mode. */ and immediate enter into 32-bit mode. */
OutU32(PCNetGetIOBase + PCNET_DW_RDP, 0);
OutU32(PCNetGetIOBase() + PCNET_DW_RDP, 0);
} }
U0 PCNetWriteRAP(U32 value) U0 PCNetWriteRAP(U32 value)
@ -148,7 +164,8 @@ U0 PCNetWriteRAP(U32 value)
Summary: Register Address Pointer register Summary: Register Address Pointer register
value will indicate which CSR / BCR register value will indicate which CSR / BCR register
we want to access in RDP / BDP. */ 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) U0 PCNetWriteCSR(U32 csr, U32 value)
@ -157,8 +174,9 @@ U0 PCNetWriteCSR(U32 csr, U32 value)
accessed via the RDP (Register Data Port). accessed via the RDP (Register Data Port).
Which CSR is selected is based on the value Which CSR is selected is based on the value
in the RAP. */ in the RAP. */
PCNetWriteRAP(csr); PCNetWriteRAP(csr);
OutU32(PCNetGetIOBase + PCNET_DW_RDP, value); OutU32(PCNetGetIOBase() + PCNET_DW_RDP, value);
} }
U32 PCNetReadCSR(U32 csr) U32 PCNetReadCSR(U32 csr)
@ -167,8 +185,9 @@ U32 PCNetReadCSR(U32 csr)
accessed via the RDP (Register Data Port). accessed via the RDP (Register Data Port).
Which CSR is selected is based on the value Which CSR is selected is based on the value
in the RAP. */ in the RAP. */
PCNetWriteRAP(csr); PCNetWriteRAP(csr);
return InU32(PCNetGetIOBase + PCNET_DW_RDP); return InU32(PCNetGetIOBase() + PCNET_DW_RDP);
} }
U0 PCNetSetSWStyle() U0 PCNetSetSWStyle()
@ -179,10 +198,13 @@ U0 PCNetSetSWStyle()
initialization block. In PCINet-PCI mode, CSR4 bits initialization block. In PCINet-PCI mode, CSR4 bits
function as defined in the datasheet , and TMD1[29] function as defined in the datasheet , and TMD1[29]
functions as ADD_FCS. */ functions as ADD_FCS. */
U32 csr = PCNetReadCSR(PCNET_CSR_SOFTWARESTYLE); 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. csr |= PCNET_SWSTYLE_SELECTION; // set SWSTYLE to PCNet-PCI mode.
Bts(&csr, PCNET_SWSTYLE_SSIZE32); // set SSIZE32 bit 1
PCNetWriteCSR(PCNET_CSR_SOFTWARESTYLE, csr); PCNetWriteCSR(PCNET_CSR_SOFTWARESTYLE, csr);
} }
@ -192,11 +214,16 @@ U0 PCNetGetMAC()
MAC address stored at first 6 bytes of PCNet EEPROM. MAC address stored at first 6 bytes of PCNet EEPROM.
EEPROM addresses shadow-copied to APROM at hardware init. EEPROM addresses shadow-copied to APROM at hardware init.
APROM accessible at first 16 bytes of PCI IO space. */ APROM accessible at first 16 bytes of PCI IO space. */
I64 i; I64 i;
ZenithLog("PCNET GET MAC: Getting VM MAC.\n");
ZenithLog(" ");
for (i = 0; i < 6; i++) 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) 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. 12 bits of 2s-complement of desired length.
Bits 0-11 of a DE are for the buffer byte count (BCNT), 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) */ 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. 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. 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 this is a Receive DE, give ownership to the card so the PCNet can fill them.
if (is_rx) if (is_rx)
Bts(&entry->status1, PCNET_DESCRIPTORf_OWN); Bts(&entry->status1, PCNET_DESCRIPTORf_OWN);
ClassRep(entry);
// ClassRep(entry);
} }
U0 PCNetAllocateBuffers() U0 PCNetAllocateBuffers()
@ -228,6 +256,7 @@ U0 PCNetAllocateBuffers()
/* AMD PCNet datasheet p.1-913, p.1-990 /* AMD PCNet datasheet p.1-913, p.1-990
When SSIZE32=1, Descriptor Ring Entry Base Address When SSIZE32=1, Descriptor Ring Entry Base Address
must be on 16-byte boundary. (TDRA[3:0]=0, RDRA[3:0]=0) */ 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, pcnet.rx_de_buffer_phys = CAllocAligned(sizeof(CPCNetDescriptorEntry) * PCNET_RX_BUFF_COUNT,
16, 16,
Fs->code_heap); Fs->code_heap);
@ -253,17 +282,23 @@ U0 PCNetAllocateBuffers()
CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer; CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer;
for (de_index = 0; de_index < PCNET_RX_BUFF_COUNT; de_index++) 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; entry = pcnet.tx_de_buffer;
for (de_index = 0; de_index < PCNET_TX_BUFF_COUNT; de_index++) 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() U0 PCNetDirectInit()
{/* AMD PCNet datasheet p. 1-1021 {/* AMD PCNet datasheet p. 1-1021
Instead of setting up initialization block, Instead of setting up initialization block,
@ -288,8 +323,11 @@ U0 PCNetDirectInit()
The OR and bit-shift of 8 allows writing The OR and bit-shift of 8 allows writing
separate U8 values in the correct locations separate U8 values in the correct locations
of the CSR. */ 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)); 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)); 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)); PCNetWriteCSR(PCNET_CSR_PADR2, pcnet.mac_address[4] | (pcnet.mac_address[5] << 8));
/* AMD PCNet datasheet p.1-961, 1-962, 1-963 /* AMD PCNet datasheet p.1-961, 1-962, 1-963
@ -333,8 +371,29 @@ U0 PCNetDirectInit()
as zeroes read undefined. */ as zeroes read undefined. */
PCNetWriteCSR(PCNET_CSR_RXRINGLEN, -PCNET_RX_BUFF_COUNT & 0xFFFF); PCNetWriteCSR(PCNET_CSR_RXRINGLEN, -PCNET_RX_BUFF_COUNT & 0xFFFF);
PCNetWriteCSR(PCNET_CSR_TXRINGLEN, -PCNET_TX_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() U0 PCNetSetInterruptCSR()
@ -344,6 +403,7 @@ U0 PCNetSetInterruptCSR()
We set Big-Endian disabled, RX interrupts We set Big-Endian disabled, RX interrupts
enabled, Init Done interrupt disabled, and TX interrupt enabled, Init Done interrupt disabled, and TX interrupt
disabled. */ disabled. */
U32 csr = PCNetReadCSR(PCNET_CSR_INTERRUPTS); U32 csr = PCNetReadCSR(PCNET_CSR_INTERRUPTS);
Btr(&csr, PCNET_INT_BSWP); Btr(&csr, PCNET_INT_BSWP);
@ -360,12 +420,12 @@ U0 PCNetEnableTXAutoPad()
Setting bit 11 (Auto Pad Transmit) allows Setting bit 11 (Auto Pad Transmit) allows
shoft transmit frames to be automatically shoft transmit frames to be automatically
extended to 64 bytes. */ extended to 64 bytes. */
U32 csr = PCNetReadCSR(PCNET_CSR_FEATURECTRL); U32 csr = PCNetReadCSR(PCNET_CSR_FEATURECTRL);
Bts(&csr, PCNET_FEATURE_APADXMT); Bts(&csr, PCNET_FEATURE_APADXMT);
PCNetWriteCSR(PCNET_CSR_FEATURECTRL, csr); PCNetWriteCSR(PCNET_CSR_FEATURECTRL, csr);
} }
U0 PCNetExitConfigMode() U0 PCNetExitConfigMode()
@ -375,6 +435,7 @@ U0 PCNetExitConfigMode()
and STOP are cleared and START bit and STOP are cleared and START bit
is set, in Status and Control Register is set, in Status and Control Register
(CSR0). */ (CSR0). */
U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS);
Btr(&csr, PCNET_CTRL_INIT); Btr(&csr, PCNET_CTRL_INIT);
@ -382,14 +443,15 @@ U0 PCNetExitConfigMode()
Bts(&csr, PCNET_CTRL_STRT); Bts(&csr, PCNET_CTRL_STRT);
PCNetWriteCSR(PCNET_CSR_CTRLSTATUS, csr);
} }
I64 PCNetDriverOwns(CPCNetDescriptorEntry* entry) I64 PCNetDriverOwns(CPCNetDescriptorEntry* entry)
{/* Returns whether the value of the OWN bit of the {/* Returns whether the value of the OWN bit of the
Descriptor Entry is zero. If 0, driver owns, Descriptor Entry is zero. If 0, driver owns,
if 1, PCNet card owns it. */ 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) I64 PCNetAllocateTransmitPacket(U8 **packet_buffer_out, I64 length)
@ -405,18 +467,22 @@ I64 PCNetAllocateTransmitPacket(U8 **packet_buffer_out, I64 length)
if (length > 0xFFF) if (length > 0xFFF)
{ // Max packet length must fit into BCNT 12-bit register. { // 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'); 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)) 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. 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); 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); *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; return de_index;
} }
U0 PCNetFinishTransmitPacket(I64 de_index) U0 PCNetFinishTransmitPacket(I64 de_index)
{/* Release ownership of the packet to the PCNet card {/* Release ownership of the packet to the PCNet card
by setting the OWN bit to 1. */ 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); 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 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 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. */ 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; 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; 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_buffer_out = pcnet.rx_buffer_addr + (de_index * ETHERNET_FRAME_SIZE);
*packet_length_out = packet_length; *packet_length_out = packet_length;
return de_index;
return de_index;
} }
U0 PCNetReleaseReceivePacket(I64 de_index) U0 PCNetReleaseReceivePacket(I64 de_index)
{/* Release ownership of the packet to the PCNet card {/* Release ownership of the packet to the PCNet card
by setting the OWN bit to 1. */ 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); Bts(&entry->status1, PCNET_DESCRIPTORf_OWN);
} }
@ -498,18 +572,19 @@ interrupt U0 PCNetIRQ()
I64 de_index; I64 de_index;
U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS); 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; CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer;
while (PCNetDriverOwns(&entry[pcnet.current_rx_de_index])) 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); de_index = PCNetReceivePacket(&packet_buffer, &packet_length);
if (de_index >= 0) // necessary? check increment logic in PCNetReceivePacket. 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); NetQueuePushCopy(packet_buffer, packet_length);
PCNetReleaseReceivePacket(de_index); PCNetReleaseReceivePacket(de_index);
} }
@ -524,8 +599,8 @@ interrupt U0 PCNetIRQ()
U0 PCIRerouteInterrupts(I64 base) U0 PCIRerouteInterrupts(I64 base)
{ // todo: comments explaining process, maybe better var names { // todo: comments explaining process, maybe better var names
I64 i; I64 i;
U8 *da = dev.uncached_alias + IOAPIC_REG; U8 *da = dev.uncached_alias + IOAPIC_REG;
U32 *_d = dev.uncached_alias + IOAPIC_DATA; U32 *_d = dev.uncached_alias + IOAPIC_DATA;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -567,6 +642,13 @@ U0 PCNetInit()
PCNetEnter32BitMode; 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; PCNetSetSWStyle;
PCNetGetMAC; PCNetGetMAC;
@ -574,26 +656,49 @@ U0 PCNetInit()
PCNetAllocateBuffers; PCNetAllocateBuffers;
PCNetDirectInit; // PCNetDirectInit;
U8 *setup = PCNetInitBlockSetup();
PCNetSetInterruptCSR; PCNetSetInterruptCSR;
PCNetEnableTXAutoPad; 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; PCNetExitConfigMode;
PCNetSetupInterrupts; PCNetSetupInterrupts;
Sleep(100);//? necessary? Sleep(100);//? necessary?
ClassRep(&pcnet); /* ClassRep(&pcnet);
"pcnet->rx_de_buffer: %X\n", pcnet.rx_de_buffer; "pcnet->rx_de_buffer: %X\n", pcnet.rx_de_buffer;
"pcnet->tx_de_buffer: %X\n", pcnet.tx_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.rx_de_buffer_phys;
"pcnet->rx_de_buffer_phys: %X\n", pcnet.tx_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, 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! //need to see if 3 years later VirtualBox supports APAD_XMT!
if (packet_length < ETHERNET_MIN_FRAME_SIZE) if (packet_length < ETHERNET_MIN_FRAME_SIZE)
{
ZenithWarn("ETHERNET FRAME ALLOCATE: PCNET APAD XMT TRUNCATE ? ...\n");
packet_length = ETHERNET_MIN_FRAME_SIZE; packet_length = ETHERNET_MIN_FRAME_SIZE;
}
de_index = PCNetAllocateTransmitPacket(&ethernet_frame, ETHERNET_MAC_HEADER_LENGTH + packet_length); de_index = PCNetAllocateTransmitPacket(&ethernet_frame, ETHERNET_MAC_HEADER_LENGTH + packet_length);
if (de_index < 0) 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. return -1; // Positive value expected. Functions calling this must factor this in.
} }
MemCopy(ethernet_frame, destination_address, MAC_ADDRESS_LENGTH); MemCopy(ethernet_frame, destination_address, MAC_ADDRESS_LENGTH);
MemCopy(ethernet_frame + MAC_ADDRESS_LENGTH, source_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; ethernet_frame[ETHERNET_ETHERTYPE_OFFSET + 1] = ethertype & 0xFF;
*packet_buffer_out = ethernet_frame + ETHERNET_MAC_HEADER_LENGTH; *packet_buffer_out = ethernet_frame + ETHERNET_MAC_HEADER_LENGTH;
@ -639,5 +747,5 @@ U8 *EthernetGetMAC()
return pcnet.mac_address; return pcnet.mac_address;
} }
PCNetInit;
PCNetInit;

View file

@ -35,6 +35,8 @@
#define AF_INET 2 #define AF_INET 2
#define AF_INET6 10 #define AF_INET6 10
#define INADDR_ANY 0
#define INET_ADDRSTRLEN 16 //pubs.opengroup.com netinit/in.h #define INET_ADDRSTRLEN 16 //pubs.opengroup.com netinit/in.h
#define INET6_ADDRSTRLEN 46 #define INET6_ADDRSTRLEN 46
@ -70,7 +72,8 @@ class CIPAddressStorage
class CSocketAddressIPV4 class CSocketAddressIPV4
{ {
I16 family; // 'AF_INET' // I16 family; // 'AF_INET'
U16 family; // 'AF_INET'
U16 port; // 'in Network Byte order' ... Big Endian U16 port; // 'in Network Byte order' ... Big Endian
CIPV4Address address; CIPV4Address address;
U8 zeroes[8]; // 'same size as socket 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) Bool IPV4AddressParse(U8 *string, U32 *destination)
{ {
// U8* lexable_string; // U8* lexable_string;
@ -159,12 +178,12 @@ Bool IPV4AddressParse(U8 *string, U32 *destination)
case TK_I64: case TK_I64:
if (cc->cur_i64 > 255 || cc->cur_i64 < 0) 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; return FALSE;
} }
if (current_section > 3) 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; return FALSE;
} }
@ -176,7 +195,7 @@ Bool IPV4AddressParse(U8 *string, U32 *destination)
break; break;
default: default:
ZenithErr("Expected decimal. \n"); ZenithErr("IPV4 ADDRESS PARSE: Expected decimal. \n");
return FALSE; return FALSE;
} }
break; break;
@ -189,7 +208,7 @@ Bool IPV4AddressParse(U8 *string, U32 *destination)
break; break;
default: default:
ZenithErr("Expected dot. \n"); ZenithErr("IPV4 ADDRESS PARSE: Expected dot. \n");
return FALSE; return FALSE;
} }
break; break;
@ -275,11 +294,17 @@ U8 *NetworkToPresentation(I64 address_family, CIPAddressStorage *source)
ipv4_source = 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[3],
ipv4_source->address.u8[2], ipv4_source->address.u8[2],
ipv4_source->address.u8[1], 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; break;
case AF_INET6: case AF_INET6:

View file

@ -0,0 +1,4 @@
#include "C:/Home/Net/DHCP"
#include "C:/Home/Net/NetHandlerTask"
NetConfigure;

16
src/Home/Net/Tests/DNSTest1.CC Executable file
View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -1,6 +1,6 @@
//#include "IPV4" //#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 "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 "Sockets"
#define UDP_MAX_PORT 65535 #define UDP_MAX_PORT 65535
@ -21,6 +21,9 @@ class CUDPSocket
I64 receive_len; I64 receive_len;
CSocketAddressStorage receive_address; // based on ->family, cast or assign to a var as IPV4/IPV6 CSocketAddress CSocketAddressStorage receive_address; // based on ->family, cast or assign to a var as IPV4/IPV6 CSocketAddress
U16 bound_to; // represents the currently bound port 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) 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; CUDPTreeQueue *temp_queue = node->queue;
CSocketAddressIPV4 *temp_ip; CSocketAddressIPV4 *temp_ip;
if (node->queue) if (temp_queue)
{ {
if (node->queue->socket->receive_address.family == AF_INET) do
{
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)
{ {
if (temp_queue->socket->receive_address.family == AF_INET) if (temp_queue->socket->receive_address.family == AF_INET)
{ {
temp_ip = &temp_queue->socket->receive_address; 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; return temp_queue;
}
} }
temp_queue = temp_queue->next; temp_queue = temp_queue->next;
} }
while (temp_queue != node->queue);
} }
return NULL;
return NULL;
} }
CUDPTreeQueue *UDPTreeNodeQueueSocketSinglePop(CUDPSocket *socket, CUDPTreeNode *node) CUDPTreeQueue *UDPTreeNodeQueueSocketSinglePop(CUDPSocket *socket, CUDPTreeNode *node)
@ -342,7 +346,7 @@ I64 UDPPacketAllocate(U8 **frame_out,
sizeof(CUDPHeader) + length); sizeof(CUDPHeader) + length);
if (de_index < 0) if (de_index < 0)
{ {
ZenithLog("UDP Ethernet Frame Allocate failed.\n"); ZenithLog("UDP PACKET ALLOCATE: Ethernet Frame Allocate failed.\n");
return de_index; return de_index;
} }
@ -353,8 +357,11 @@ I64 UDPPacketAllocate(U8 **frame_out,
header->length = EndianU16(sizeof(CUDPHeader) + length); header->length = EndianU16(sizeof(CUDPHeader) + length);
header->checksum = 0; header->checksum = 0;
// ClassRep(header);
*frame_out = ethernet_frame + sizeof(CUDPHeader); *frame_out = ethernet_frame + sizeof(CUDPHeader);
return de_index;
} }
U0 UDPPacketFinish(I64 de_index) U0 UDPPacketFinish(I64 de_index)
@ -414,13 +421,13 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
break; break;
default: 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; return -1;
} }
if (udp_socket->bound_to) 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; return -1;
} }
@ -430,7 +437,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
if (udp_socket->receive_address.family == AF_INET6) 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; return -1;
} }
@ -448,7 +455,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
if (udp_socket->receive_address.family == AF_INET) 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; return -1;
} }
@ -464,7 +471,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
break; break;
case AF_UNSPEC: case AF_UNSPEC:
Debug("TODO: AF_UNSPEC UDP BIND"); Debug("TODO: AF_UNSPEC UDP BIND -- param family");
break; break;
} }
@ -481,9 +488,10 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
switch (address_source->family) switch (address_source->family)
{ {
case AF_INET: case AF_INET:
// TODO: will any INADDR_ANY sockets bound at the port break this?
if (UDPTreeNodeQueueIPV4Find(ipv4_receive->address.address, temp_node)) 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; return -1;
} }
else else
@ -496,7 +504,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
break; break;
case AF_UNSPEC: case AF_UNSPEC:
Debug("TODO: AF_UNSPEC UDP BIND"); Debug("TODO: AF_UNSPEC UDP BIND -- found in bound tree");
break; break;
} }
} }
@ -524,7 +532,7 @@ I64 UDPSocketBind(CUDPSocket *udp_socket, CSocketAddressStorage *address_source)
break; break;
default: default:
ZenithErr("Unsuccessful UDP Socket Bind: Misconfigured Socket state-machine.\n"); ZenithErr("UDP SOCKET BIND: Failed, Misconfigured Socket state-machine.\n");
return -1; return -1;
} }
@ -585,7 +593,7 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd
break; break;
default: 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; return -1;
} }
@ -595,11 +603,14 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd
if (udp_socket->receive_timeout_ms != 0) if (udp_socket->receive_timeout_ms != 0)
udp_socket->receive_max_timeout = counts.jiffies + udp_socket->receive_timeout_ms * JIFFY_FREQ / 1000; 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) while (udp_socket->receive_buffer != NULL)
{ // 'Check for timeout' { // 'Check for timeout'
if (udp_socket->receive_timeout_ms != 0 && counts.jiffies > udp_socket->receive_max_timeout) if (udp_socket->receive_timeout_ms != 0 && counts.jiffies > udp_socket->receive_max_timeout)
{ // Shrine has TODO: 'seterror(EWOULDBLOCK)' investigate this { // Shrine has TODO: 'seterror(EWOULDBLOCK)' investigate this
udp_socket->receive_len = -1; // ? udp_socket->receive_len = -1; // ?
ZenithErr("UDP SOCKET RECEIVE FROM: Timed out.\n");
break; break;
} }
@ -608,15 +619,18 @@ I64 UDPSocketReceiveFrom(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAdd
if (address_out) if (address_out)
{ {
switch (udp_socket->receive_address.family) // switch (udp_socket->receive_address.family)
switch (udp_socket->from_address.family)
{ {
case AF_INET: case AF_INET:
ipv4_socket_addr = address_out; 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; break;
case AF_INET6: case AF_INET6:
ipv6_socket_addr = address_out; 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; break;
case AF_UNSPEC: case AF_UNSPEC:
Debug("TODO: UDP Receive From Error AF_UNSPEC UDPSocket Address Family\n"); 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. break; // and use stored address as send address.
case SOCKET_STATE_READY: // If socket state is initial, attempt to bind it to destination. 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); UDPSocketBind(udp_socket, destination_addr);
dest = destination_addr; dest = destination_addr;
break; break;
default: 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; return -1;
} }
@ -689,21 +703,29 @@ I64 UDPSocketSendTo(CUDPSocket *udp_socket, U8 *buffer, I64 len, CSocketAddressS
I64 UDPHandler(CIPV4Packet *packet) I64 UDPHandler(CIPV4Packet *packet)
{ // TODO: Need either two UDP handlers for IPv4/IPv6, or logic changes if IPV6 is desired. { // TODO: Need either two UDP handlers for IPv4/IPv6, or logic changes if IPV6 is desired.
U16 source_port; U16 source_port;
U16 destination_port; U16 destination_port;
U8 *data; U8 *data;
I64 length; I64 length;
CUDPTreeNode *node; CUDPTreeNode *node;
CUDPTreeQueue *queue; CUDPTreeQueue *queue;
CUDPSocket *udp_socket; CUDPSocket *udp_socket;
CSocketAddressIPV4 *ipv4_addr; CSocketAddressIPV4 *ipv4_addr;
I64 num_receive; 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); I64 error = UDPParsePacket(&source_port, &destination_port, &data, &length, packet);
if (error < 0) if (error < 0)
{ {
ZenithErr("UDP Handler Packet Parse Error.\n"); ZenithErr("UDP HANDLER: Packet Parse Error.\n");
return error; return error;
} }
@ -712,41 +734,44 @@ I64 UDPHandler(CIPV4Packet *packet)
node = UDPTreeNodeFind(destination_port, udp_globals.bound_socket_tree); node = UDPTreeNodeFind(destination_port, udp_globals.bound_socket_tree);
if (node) 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!! queue = UDPTreeNodeQueueIPV4Find(packet->destination_ip_address, node); // TODO: make sure bit order is correct here!!
if (queue) if (queue)
{ {
udp_socket = queue->socket; 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 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; return -1;
} }
} }
else 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; return -1;
} }
} }
else else
{ {
ZenithWarn("Handled UDP packet but socket tree is currently empty.\n"); ZenithWarn("UDP HANDLER: Socket tree is currently empty.\n");
return -1; 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. // at this point, udp_socket is set, otherwise has already returned -1.
if (udp_socket->receive_buffer) 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; num_receive = udp_socket->receive_len;
if (num_receive > length) if (num_receive > length)
{ {
ZenithWarn("UDP HANDLER: Truncating UDP socket receive length. num_receive , len : %d, %d\n",
num_receive, length);
num_receive = length; num_receive = length;
ZenithWarn("UDP Handler: Truncating UDP socket receive length.\n");
} }
MemCopy(udp_socket->receive_buffer, data, num_receive); MemCopy(udp_socket->receive_buffer, data, num_receive);
@ -759,10 +784,13 @@ I64 UDPHandler(CIPV4Packet *packet)
udp_socket->receive_buffer = NULL; udp_socket->receive_buffer = NULL;
udp_socket->receive_len = num_receive; 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->port = EndianU16(source_port);
ipv4_addr->address.address = EndianU32(packet->source_ip_address); 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; return error;