aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2020-09-27 13:17:55 +0200
committerMarvin Borner2020-09-27 13:17:55 +0200
commit9286bba7b273301dd777dd15feec40492ccd9a03 (patch)
tree680be140917394568830ef7efc14cb79b77bb671
parentcac7c352a1ece2744de42128a9c69df16f05d26a (diff)
Added UDP, DHCP, ARP
Quite awesome, IMHO
-rw-r--r--kernel/Makefile3
-rw-r--r--kernel/drivers/rtl8139.c6
-rw-r--r--kernel/features/net.c263
-rw-r--r--kernel/inc/net.h56
-rw-r--r--kernel/inc/rtl8139.h2
-rwxr-xr-xrun2
6 files changed, 317 insertions, 15 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 1fc024f..599412e 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -23,7 +23,8 @@ LD = ../cross/opt/bin/i686-elf-ld
OC = ../cross/opt/bin/i686-elf-objcopy
AS = nasm
-CFLAGS = -Wall -Wextra -Wno-address-of-packed-member -nostdlib -nostdinc -ffreestanding -fno-builtin -mno-red-zone -mgeneral-regs-only -std=c99 -m32 -pedantic-errors -Wl,-ekernel_main -I../libc/inc/ -Iinc/ -Dkernel -Ofast
+# TODO: Fix -Ofast crash
+CFLAGS = -Wall -Wextra -Wno-address-of-packed-member -nostdlib -nostdinc -ffreestanding -fno-builtin -mno-red-zone -mgeneral-regs-only -std=c99 -m32 -pedantic-errors -Wl,-ekernel_main -I../libc/inc/ -Iinc/ -Dkernel -O0
ASFLAGS = -f elf32
diff --git a/kernel/drivers/rtl8139.c b/kernel/drivers/rtl8139.c
index 2fc8f07..4a5ed16 100644
--- a/kernel/drivers/rtl8139.c
+++ b/kernel/drivers/rtl8139.c
@@ -25,7 +25,6 @@ u8 *rtl8139_get_mac()
void rtl8139_receive_packet()
{
- printf("%x\n", current_packet_ptr);
u16 *t = (u16 *)(rx_buffer + current_packet_ptr);
u16 length = *(t + 1);
t += 2;
@@ -47,7 +46,7 @@ static u8 tsd_array[4] = { 0x10, 0x14, 0x18, 0x1C };
static u8 tx_current = 0;
void rtl8139_send_packet(void *data, u32 len)
{
- printf("Sending packet %d\n", len);
+ printf("Sending packet %d\n\n", len);
outl(rtl_iobase + tsad_array[tx_current], (u32)data);
outl(rtl_iobase + tsd_array[tx_current++], len);
if (tx_current > 3)
@@ -125,7 +124,7 @@ void rtl8139_init()
irq_install_handler(rtl_irq, rtl8139_irq_handler);
}
-void rtl8139_install()
+int rtl8139_install()
{
pci_scan(&rtl8139_find, -1, &rtl_device_pci);
@@ -133,4 +132,5 @@ void rtl8139_install()
print("Found rtl8139 card\n");
rtl8139_init();
}
+ return rtl_device_pci;
}
diff --git a/kernel/features/net.c b/kernel/features/net.c
index 1ebccb5..2d96e5f 100644
--- a/kernel/features/net.c
+++ b/kernel/features/net.c
@@ -6,9 +6,12 @@
#include <pci.h>
#include <print.h>
#include <rtl8139.h>
+#include <str.h>
+
+static int is_ip_allocated, ip_addr;
/**
- * Checksums
+ * Helper functions
*/
u16 ip_calculate_checksum(struct ip_packet *packet)
@@ -25,12 +28,29 @@ u16 ip_calculate_checksum(struct ip_packet *packet)
return sum;
}
+void *dhcp_get_options(struct dhcp_packet *packet, u8 type)
+{
+ u8 *options = packet->options + 4;
+ u8 curr_type = *options;
+ while (curr_type != 0xff) {
+ u8 len = *(options + 1);
+ if (curr_type == type) {
+ void *ret = malloc(len);
+ memcpy(ret, options + 2, len);
+ return ret;
+ }
+ options += (2 + len);
+ }
+ return NULL;
+}
+
/**
* Requests
*/
-int ethernet_send_packet(u8 *dst, u8 *data, int len, int prot)
+void ethernet_send_packet(u8 *dst, u8 *data, int len, int prot)
{
+ print("Ethernet send packet\n");
struct ethernet_packet *packet = malloc(sizeof(*packet) + len);
memcpy(packet->src, rtl8139_get_mac(), 6);
memcpy(packet->dst, dst, 6);
@@ -38,11 +58,32 @@ int ethernet_send_packet(u8 *dst, u8 *data, int len, int prot)
packet->type = htons(prot);
rtl8139_send_packet(packet, sizeof(*packet) + len);
free(packet);
- return len;
}
+static u8 broadcast_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+void arp_send_packet(u8 *dst_mac, u32 dst_protocol_addr)
+{
+ print("ARP send packet\n");
+ struct arp_packet *packet = malloc(sizeof(*packet));
+
+ memcpy(packet->src_mac, rtl8139_get_mac(), 6);
+ packet->src_protocol_addr = 0x0e02000a;
+ memcpy(packet->dst_mac, dst_mac, 6);
+ packet->dst_protocol_addr = dst_protocol_addr;
+ packet->opcode = htons(ARP_REQUEST);
+ packet->hardware_addr_len = 6;
+ packet->protocol_addr_len = 4;
+ packet->hardware_type = htons(HARDWARE_TYPE_ETHERNET);
+ packet->protocol = htons(ETHERNET_TYPE_IP4);
+
+ ethernet_send_packet(broadcast_mac, (u8 *)packet, sizeof(*packet), ETHERNET_TYPE_ARP);
+ free(packet);
+}
+
+int arp_lookup(u8 *ret_hardware_addr, u32 ip_addr);
void ip_send_packet(u32 dst, void *data, int len, int prot)
{
+ print("IP send packet\n");
struct ip_packet *packet = malloc(sizeof(*packet) + len);
memset(packet, 0, sizeof(*packet));
packet->version_ihl = ((0x4 << 4) | (0x5 << 0));
@@ -50,15 +91,53 @@ void ip_send_packet(u32 dst, void *data, int len, int prot)
packet->id = 0; // TODO: IP fragmentation
packet->ttl = 64;
packet->protocol = prot;
- packet->src = htonl(0x0a00022a);
+ packet->src = is_ip_allocated ? ip_addr : 0x0e02000a;
packet->dst = dst;
- /* void *packet_data = (u32 *)packet + 0x5 * 4; */
memcpy(packet->data, data, len);
packet->length = htons(sizeof(*packet) + len);
packet->checksum = htons(ip_calculate_checksum(packet));
- // TODO: arp destination lookup
- ethernet_send_packet((u8 *)0x424242424242, (u8 *)packet, htons(packet->length),
- ETHERNET_TYPE_IP4);
+
+ u8 dst_mac[6];
+
+ int arp_sent = 3;
+ u8 zero_hardware_addr[] = { 0, 0, 0, 0, 0, 0 };
+ while (!arp_lookup(dst_mac, dst)) {
+ if (arp_sent != 0) {
+ arp_sent--;
+ arp_send_packet(zero_hardware_addr, dst);
+ }
+ }
+ /* printf("%x:%x:%x:%x:%x:%x\n", dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], */
+ /* dst_mac[5]); */
+ ethernet_send_packet(dst_mac, (u8 *)packet, htons(packet->length), ETHERNET_TYPE_IP4);
+
+ free(packet);
+}
+
+void udp_send_packet(u32 dst, u16 src_port, u16 dst_port, void *data, int len)
+{
+ print("UDP send packet\n");
+ int length = sizeof(struct udp_packet) + len;
+ struct udp_packet *packet = malloc(length);
+ memset(packet, 0, sizeof(struct udp_packet));
+ packet->src_port = htons(src_port);
+ packet->dst_port = htons(dst_port);
+ packet->length = htons(length);
+ packet->checksum = 0; // Optional
+
+ memcpy(packet->data, data, len);
+ ip_send_packet(dst, packet, length, IP_PROT_UDP);
+ free(packet);
+}
+
+void dhcp_make_packet(struct dhcp_packet *packet, u8 msg_type, u32 request_ip);
+void dhcp_request(u32 request_ip)
+{
+ u32 dst = 0xffffffff;
+ struct dhcp_packet *packet = malloc(sizeof(*packet));
+ memset(packet, 0, sizeof(*packet));
+ dhcp_make_packet(packet, 3, request_ip);
+ udp_send_packet(dst, 68, 67, packet, sizeof(*packet));
free(packet);
}
@@ -77,6 +156,31 @@ void icmp_handle_packet(u32 dst, int len)
free(packet);
}
+void dhcp_handle_packet(struct dhcp_packet *packet)
+{
+ print("DHCP!\n");
+ if (packet->op == DHCP_REPLY) {
+ u8 *type = dhcp_get_options(packet, 53);
+ if (*type == 2) {
+ dhcp_request(packet->your_ip);
+ } else if (*type == 5) {
+ print("ACK!\n");
+ ip_addr = packet->your_ip;
+ is_ip_allocated = 1;
+ }
+ free(type);
+ }
+}
+
+void udp_handle_packet(struct udp_packet *packet)
+{
+ void *data_ptr = (u32 *)packet + sizeof(*packet);
+
+ if (ntohs(packet->dst_port) == 68)
+ dhcp_handle_packet(data_ptr);
+ return;
+}
+
void ip_handle_packet(struct ip_packet *packet, int len)
{
switch (packet->protocol) {
@@ -89,18 +193,60 @@ void ip_handle_packet(struct ip_packet *packet, int len)
break;
case IP_PROT_UDP:
print("UDP Packet!\n");
+ udp_handle_packet((struct udp_packet *)packet->data);
break;
default:
printf("Unknown IP protocol %d\n", packet->protocol);
}
}
+static struct arp_table_entry arp_table[512];
+static int arp_table_size;
+static int arp_table_curr;
+void arp_handle_packet(struct arp_packet *packet, int len)
+{
+ (void)len;
+ u8 dst_mac[6];
+ memcpy(dst_mac, packet->src_mac, 6);
+ u32 dst_protocol_addr = packet->src_protocol_addr;
+ if (ntohs(packet->opcode) == ARP_REQUEST) {
+ print("Got ARP request\n");
+ u32 my_ip = 0x0e02000a;
+ if (packet->dst_protocol_addr == my_ip) {
+ memcpy(packet->src_mac, rtl8139_get_mac(), 6);
+ packet->src_protocol_addr = my_ip;
+ memcpy(packet->dst_mac, dst_mac, 6);
+ packet->dst_protocol_addr = dst_protocol_addr;
+ packet->opcode = htons(ARP_REPLY);
+ packet->hardware_addr_len = 6;
+ packet->protocol_addr_len = 4;
+ packet->hardware_type = htons(HARDWARE_TYPE_ETHERNET);
+ packet->protocol = htons(ETHERNET_TYPE_IP4);
+ ethernet_send_packet(dst_mac, (u8 *)packet, sizeof(*packet),
+ ETHERNET_TYPE_ARP);
+ }
+ } else if (ntohs(packet->opcode) == ARP_REPLY) {
+ print("Got ARP reply");
+ } else {
+ printf("Got unknown ARP, opcode = %d\n", packet->opcode);
+ }
+
+ // Store
+ arp_table[arp_table_curr].ip_addr = dst_protocol_addr;
+ memcpy(&arp_table[arp_table_curr].mac_addr, dst_mac, 6);
+ if (arp_table_size < 512)
+ arp_table_size++;
+ if (arp_table_curr >= 512)
+ arp_table_curr = 0;
+}
+
void ethernet_handle_packet(struct ethernet_packet *packet, int len)
{
void *data = packet->data;
int data_len = len - sizeof(*packet);
if (ntohs(packet->type) == ETHERNET_TYPE_ARP) {
print("ARP PACKET\n");
+ arp_handle_packet(data, data_len);
} else if (ntohs(packet->type) == ETHERNET_TYPE_IP4) {
print("IP4 PACKET\n");
ip_handle_packet(data, data_len);
@@ -113,10 +259,109 @@ void ethernet_handle_packet(struct ethernet_packet *packet, int len)
}
/**
+ * DHCP
+ */
+
+void dhcp_make_packet(struct dhcp_packet *packet, u8 msg_type, u32 request_ip)
+{
+ packet->op = DHCP_REQUEST;
+ packet->hardware_type = HARDWARE_TYPE_ETHERNET;
+ packet->hardware_addr_len = 6;
+ packet->hops = 0;
+ packet->xid = htonl(DHCP_TRANSACTION_IDENTIFIER);
+ packet->flags = htons(0x8000);
+ memcpy(packet->client_hardware_addr, rtl8139_get_mac(), 6);
+
+ // Magic Cookie
+ u8 *options = packet->options;
+ *((u32 *)(options)) = htonl(0x63825363);
+ options += 4;
+
+ // First option, message type = DHCP_DISCOVER/DHCP_REQUEST
+ *(options++) = 53;
+ *(options++) = 1;
+ *(options++) = msg_type;
+
+ // Client identifier
+ *(options++) = 61;
+ *(options++) = 0x07;
+ *(options++) = 0x01;
+ memcpy(options, rtl8139_get_mac(), 6);
+ options += 6;
+
+ // Requested IP address
+ *(options++) = 50;
+ *(options++) = 0x04;
+ *((u32 *)(options)) = htonl(0x0a00020e);
+ *((u32 *)(options)) = request_ip;
+ options += 4;
+
+ // Host Name
+ *(options++) = 12;
+ *(options++) = 0x07;
+ memcpy(options, "melvix", strlen("melvix"));
+ options += strlen("melvix");
+ *(options++) = 0x00;
+
+ // Parameter request list
+ *(options++) = 55;
+ *(options++) = 8;
+ *(options++) = 0x1;
+ *(options++) = 0x3;
+ *(options++) = 0x6;
+ *(options++) = 0xf;
+ *(options++) = 0x2c;
+ *(options++) = 0x2e;
+ *(options++) = 0x2f;
+ *(options++) = 0x39;
+ *(options++) = 0xff;
+}
+
+void dhcp_discover()
+{
+ print("DHCP discover\n");
+ u32 request_ip = 0;
+ u32 dst_ip = 0xffffffff;
+ struct dhcp_packet *packet = malloc(sizeof(*packet));
+ memset(packet, 0, sizeof(*packet));
+ dhcp_make_packet(packet, 1, request_ip);
+ udp_send_packet(dst_ip, 68, 67, packet, sizeof(*packet));
+ free(packet);
+}
+
+/**
+ * ARP
+ */
+
+void arp_lookup_add(u8 *ret_hardware_addr, u32 ip_addr)
+{
+ arp_table[arp_table_curr].ip_addr = ip_addr;
+ memcpy(&arp_table[arp_table_curr].mac_addr, ret_hardware_addr, 6);
+ if (arp_table_size < 512)
+ arp_table_size++;
+ if (arp_table_curr >= 512)
+ arp_table_curr = 0;
+}
+
+int arp_lookup(u8 *ret_hardware_addr, u32 ip_addr)
+{
+ for (int i = 0; i < 512; i++) {
+ if (arp_table[i].ip_addr == ip_addr) {
+ memcpy(ret_hardware_addr, &arp_table[i].mac_addr, 6);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
* Install
*/
void net_install()
{
- rtl8139_install();
+ if (rtl8139_install()) {
+ arp_lookup_add(broadcast_mac, 0xffffffff);
+ dhcp_discover();
+ }
}
diff --git a/kernel/inc/net.h b/kernel/inc/net.h
index 943583a..2d0dbe7 100644
--- a/kernel/inc/net.h
+++ b/kernel/inc/net.h
@@ -20,6 +20,17 @@
#define IP_PROT_TCP 0x06
#define IP_PROT_UDP 0x11
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+#define DHCP_REQUEST 1
+#define DHCP_REPLY 2
+#define DHCP_TRANSACTION_IDENTIFIER 0x55555555
+
+#define HARDWARE_TYPE_ETHERNET 0x01
+
+// Protocol structs
+
struct ethernet_packet {
u8 dst[6];
u8 src[6];
@@ -27,6 +38,18 @@ struct ethernet_packet {
u8 data[];
} __attribute__((packed));
+struct arp_packet {
+ u16 hardware_type;
+ u16 protocol;
+ u8 hardware_addr_len;
+ u8 protocol_addr_len;
+ u16 opcode;
+ u8 src_mac[6];
+ u32 src_protocol_addr;
+ u8 dst_mac[6];
+ u32 dst_protocol_addr;
+} __attribute__((packed));
+
struct ip_packet {
u8 version_ihl;
u8 dscp_ecn;
@@ -41,12 +64,45 @@ struct ip_packet {
u8 data[];
} __attribute__((packed));
+struct dhcp_packet {
+ u8 op;
+ u8 hardware_type;
+ u8 hardware_addr_len;
+ u8 hops;
+ u32 xid;
+ u16 seconds;
+ u16 flags;
+ u32 client_ip;
+ u32 your_ip;
+ u32 server_ip;
+ u32 gateway_ip;
+ u8 client_hardware_addr[16];
+ u8 server_name[64];
+ u8 file[128];
+ u8 options[64];
+} __attribute__((packed));
+
+struct udp_packet {
+ u16 src_port;
+ u16 dst_port;
+ u16 length;
+ u16 checksum;
+ u8 data[];
+} __attribute__((packed));
+
struct icmp_packet {
u8 type;
u8 version;
u16 checksum;
} __attribute__((packed));
+// Other structs
+
+struct arp_table_entry {
+ u32 ip_addr;
+ u64 mac_addr;
+};
+
void ethernet_handle_packet(struct ethernet_packet *packet, int len);
void net_install();
diff --git a/kernel/inc/rtl8139.h b/kernel/inc/rtl8139.h
index e12f315..d84d115 100644
--- a/kernel/inc/rtl8139.h
+++ b/kernel/inc/rtl8139.h
@@ -28,7 +28,7 @@
#define RTL_PORT_RXMISS 0x4C
#define RTL_PORT_CONFIG 0x52
-void rtl8139_install();
+int rtl8139_install();
void rtl8139_send_packet(void *data, u32 len);
u8 *rtl8139_get_mac();
diff --git a/run b/run
index 7ce006b..a220bee 100755
--- a/run
+++ b/run
@@ -12,7 +12,7 @@ no_ask="${2}"
qemu_with_flags() {
if [ -z "$network" ]; then network="rtl8139"; fi
if [ "$network" != "false" ] && [ "$mode" = "net" ]; then
- qemu-system-i386 -cpu max -no-reboot -vga std -rtc base=localtime -m 256M -smp 4 -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=melvix_net -device $network,netdev=melvix_net,id=melvix_nic -object filter-dump,id=melvix_nic,netdev=melvix_net,file=dump.pcap "$@"
+ qemu-system-i386 -cpu max -no-reboot -vga std -rtc base=localtime -m 256M -smp 4 -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=melvix_net -device $network,netdev=melvix_net,id=melvix_nic,mac=42:42:42:42:42:42 -object filter-dump,id=melvix_nic,netdev=melvix_net,file=dump.pcap "$@"
else
qemu-system-i386 -cpu max -no-reboot -vga std -rtc base=localtime -m 256M -smp 4 "$@"
fi