net: respond to pings?

This commit is contained in:
K. Lange 2021-06-10 20:48:48 +09:00
parent 394e4e3e0c
commit f1efda9e2a
2 changed files with 73 additions and 2 deletions

View File

@ -294,7 +294,7 @@ static int configure_interface(const char * if_name) {
gettimeofday(&end, NULL);
time_diff(&start,&end,&sec_diff,&usec_diff);
if (sec_diff > 0 || usec_diff > 500000) {
if (sec_diff > 2) {
close(netdev);
return 1;
}

View File

@ -8,11 +8,13 @@
*/
#include <errno.h>
#include <kernel/types.h>
#include <kernel/string.h>
#include <kernel/printf.h>
#include <kernel/syscall.h>
#include <kernel/vfs.h>
#include <kernel/net/netif.h>
#include <kernel/net/eth.h>
#include <sys/socket.h>
@ -30,6 +32,14 @@ struct ipv4_packet {
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
struct icmp_header {
uint8_t type;
uint8_t code;
uint16_t csum;
uint16_t rest_of_header;
uint8_t data[];
} __attribute__((packed)) __attribute__((aligned(2)));
#define IPV4_PROT_UDP 17
#define IPV4_PROT_TCP 6
@ -41,6 +51,67 @@ static void ip_ntoa(const uint32_t src_addr, char * out) {
(src_addr & 0xFF));
}
static uint16_t icmp_checksum(struct ipv4_packet * packet) {
uint32_t sum = 0;
uint16_t * s = (uint16_t *)packet->payload;
for (int i = 0; i < (ntohs(packet->length) - 20) / 2; ++i) {
sum += ntohs(s[i]);
}
if (sum > 0xFFFF) {
sum = (sum >> 16) + (sum & 0xFFFF);
}
return ~(sum & 0xFFFF) & 0xFFFF;
}
uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) {
uint32_t sum = 0;
uint16_t * s = (uint16_t *)p;
/* TODO: Checksums for options? */
for (int i = 0; i < 10; ++i) {
sum += ntohs(s[i]);
}
if (sum > 0xFFFF) {
sum = (sum >> 16) + (sum & 0xFFFF);
}
return ~(sum & 0xFFFF) & 0xFFFF;
}
static void icmp_handle(struct ipv4_packet * packet, const char * src, const char * dest, fs_node_t * nic) {
struct icmp_header * header = (void*)&packet->payload;
if (header->type == 8 && header->code == 0) {
printf("net: ping with %d bytes of payload\n", ntohs(packet->length));
if (ntohs(packet->length) & 1) packet->length++;
struct ipv4_packet * response = malloc(ntohs(packet->length));
response->length = packet->length;
response->destination = packet->source;
response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
response->ttl = 64;
response->protocol = 1;
response->ident = packet->ident;
response->flags_fragment = htons(0x4000);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
memcpy(response->payload, packet->payload, ntohs(packet->length));
struct icmp_header * ping_reply = (void*)&response->payload;
ping_reply->csum = 0;
ping_reply->type = 0;
ping_reply->csum = htons(icmp_checksum(response));
/* send ipv4... */
net_eth_send((struct EthernetDevice*)nic->device, ntohs(response->length), response, ETHERNET_TYPE_IPV4, ETHERNET_BROADCAST_MAC);
free(response);
} else {
printf("net: ipv4: %s: %s -> %s ICMP %d (code = %d)\n", nic->name, src, dest, header->type, header->code);
}
}
void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
char dest[16];
@ -51,7 +122,7 @@ void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
switch (packet->protocol) {
case 1:
printf("net: ipv4: %s: %s -> %s ICMP\n", nic->name, src, dest);
icmp_handle(packet, src, dest, nic);
break;
case IPV4_PROT_UDP:
printf("net: ipv4: %s: %s -> %s udp %d to %d\n", nic->name, src, dest, ntohs(((uint16_t*)&packet->payload)[0]), ntohs(((uint16_t*)&packet->payload)[1]));