quinn-os/tcp.c
2015-09-10 16:51:02 +10:00

136 lines
4.1 KiB
C

#include "ether.h"
#include "tcp.h"
#include "socket.h"
#include "ipv4.h"
#include "memory.h"
#include "console.h"
#include "string.h"
static inline unsigned short sum_to_checksum(unsigned int sum) {
while (sum >> 16) {
sum = (sum >> 16) + (sum & 0xFFFF);
}
return ~sum;
}
void tcp_sock_add_packet(struct socket_t *sock, struct tcp_data_t *packet) {
if (sock->tcp_packet_count == 0) {
sock->tcp_packets = (struct tcp_data_t **)malloc(sizeof(struct tcp_data_t *));
} else {
sock->tcp_packets = (struct tcp_data_t **)realloc(sock->tcp_packets, sizeof(struct tcp_data_t *) * (sock->tcp_packet_count + 1));
}
sock->tcp_packets[sock->tcp_packet_count] = packet;
sock->tcp_packet_count++;
}
void tcp_send(struct ether_t *ether, struct socket_t *sock, unsigned short flags, unsigned char *packet, unsigned int len) {
struct tcp_header_t *header = (struct tcp_header_t *)malloc(sizeof(struct tcp_header_t) + len);
header->source_port = htons(sock->port_recv);
header->dest_port = htons(sock->port_dest);
header->seq_number = htonl(sock->tcp_sock.seq_number);
header->ack_number = flags & (1<<4) ? htonl(sock->tcp_sock.ack_number) : 0;
header->flags = htons(0x5000 ^ (flags & 0xFF));
header->window = htons(1800);
header->checksum = 0; // Fill in later
header->urgent = 0;
if ((flags & 0xff) == (1<<1)) {
sock->tcp_sock.seq_number += 1;
} else {
sock->tcp_sock.seq_number += len;
}
if (packet != (void *)0 && len != 0) {
memcpy(header->payload, packet, len);
}
//data
unsigned int sum = 0;
unsigned int l = len + sizeof(struct tcp_header_t);
unsigned short *ptr = (unsigned short *)header;
for (; l > 1; l -= 2) {
sum += *ptr++;
if (sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
}
if(l & 1) {
sum += *((unsigned char *) ptr);
}
//pseudo header
sum += htons((ether->ipv4 >> 16) & 0xffff);
sum += htons(ether->ipv4 & 0xffff);
sum += htons((sock->addr >> 16) & 0xffff);
sum += htons(sock->addr & 0xffff);
sum += htons(0x06);
sum += htons(sizeof(struct tcp_header_t) + len);
header->checksum = sum_to_checksum(sum);
ipv4_send(ether, 0x06, htonl(sock->addr), header, len + sizeof(struct tcp_header_t));
}
void tcp_process_packet(struct ether_t *ether, unsigned int dest, struct tcp_header_t *packet, unsigned int len) {
// find socket
struct tcp_data_t *data;
unsigned int dlen = len - ((htons(packet->flags) >> 12) * 4);
struct socket_t *sock = socket_find(htons(packet->dest_port));
if (sock != (void *)0) {
if (sock->tcp_sock.seq_number != htonl(packet->ack_number)) {
kprintf("Warning, dropping packet, Wrong Ack Expecting %d Got %d\n", sock->tcp_sock.seq_number, htonl(packet->ack_number));
return;
}
if ((htons(packet->flags) & (1 << 1)) && (htons(packet->flags) & (1 << 4))) {
sock->tcp_sock.ack_number = htonl(packet->seq_number) + dlen + 1;
tcp_send(ether, sock, (1 << 4), (void *)0, 0);
sock->status = 2;
} else if (htons(packet->flags) & (1 << 2)) {
socket_close(sock);
return;
} else {
if (dlen == 0) {
if (htons(packet->flags) & 1) {
sock->tcp_sock.ack_number = htonl(packet->seq_number) + dlen + 1;
tcp_send(ether, sock, (1 << 4) | 1, (void *)0, 0);
socket_close(sock);
return;
}
return;
} else {
data = (struct tcp_data_t *)malloc(sizeof(struct tcp_data_t));
data->len = dlen;
}
if (data->len > 0) {
data->data = (char *)malloc(data->len);
memcpy(data->data, packet->payload, data->len);
} else {
data->data = (void *)0;
}
sock->tcp_sock.ack_number = htonl(packet->seq_number) + dlen;
/// if ((htons(packet->flags) & (1 << 1)) && (htons(packet->flags) & (1 << 4)) && dlen == 0) {
// sock->tcp_sock.ack_number += 1;
// }
tcp_sock_add_packet(sock, data);
tcp_send(ether, sock, (1 << 4), (void *)0, 0);
if (htons(packet->flags) & 1) {
sock->tcp_sock.ack_number = htonl(packet->seq_number) + dlen + 1;
tcp_send(ether, sock, (1 << 4) | 1, (void *)0, 0);
socket_close(sock);
}
}
} else {
// got data for non existant socket.
}
}