CoolPotOS/network/ipv4.c

111 lines
4.6 KiB
C

#include "../include/ipv4.h"
#include "../include/memory.h"
#include "../include/common.h"
static uint16_t ident = 0;
void IPV4ProviderSend(uint8_t protocol, uint64_t dest_mac, uint32_t dest_ip,
uint32_t src_ip, uint8_t *data, uint32_t size) {
struct IPV4Message *res =
(struct IPV4Message *)kmalloc(sizeof(struct IPV4Message) + size);
uint8_t *dat = (uint8_t *)res;
memcpy(dat + sizeof(struct IPV4Message), data, size);
res->version = 4;
res->headerLength = sizeof(struct IPV4Message) / 4;
res->tos = 0;
res->ident = ident;
res->timeToLive = 64;
res->protocol = protocol;
res->dstIP = ((dest_ip << 24) & 0xff000000) | ((dest_ip << 8) & 0x00ff0000) |
((dest_ip >> 8) & 0xff00) | ((dest_ip >> 24) & 0xff);
res->srcIP = ((src_ip << 24) & 0xff000000) | ((src_ip << 8) & 0x00ff0000) |
((src_ip >> 8) & 0xff00) | ((src_ip >> 24) & 0xff);
if (sizeof(struct IPV4Message) + size <= MTU) {
res->totalLength = swap16(sizeof(struct IPV4Message) + size);
res->flagsAndOffset = 0;
res->checkSum = 0;
res->checkSum = CheckSum((uint16_t *)dat, sizeof(struct IPV4Message));
ether_frame_provider_send(dest_mac, 0x0800, dat,
sizeof(struct IPV4Message) + size);
} else {
int offset = 0;
uint8_t *dat1 = (uint8_t *)kmalloc(MTU);
for (int i = 0; i * (MTU - sizeof(struct IPV4Message)) <= size; i++) {
if (i * (MTU - sizeof(struct IPV4Message)) >=
size - (MTU - sizeof(struct IPV4Message))) {
res->totalLength =
swap16(size - i * (MTU - sizeof(struct IPV4Message)) +
sizeof(struct IPV4Message));
res->flagsAndOffset = offset << IP_OFFSET;
res->flagsAndOffset = swap16(res->flagsAndOffset);
res->checkSum = 0;
res->checkSum = CheckSum((uint16_t *)dat, sizeof(struct IPV4Message));
memcpy((void *)dat1, (void *)res, sizeof(struct IPV4Message));
memcpy((void *)(dat1 + sizeof(struct IPV4Message)),
(void *)(data + i * (MTU - sizeof(struct IPV4Message))),
size - i * (MTU - sizeof(struct IPV4Message)));
// printk("ip:%08x,%08x
// size:%d\nMF:0\noffset:%d\n",swap32(res->srcIP),swap32(res->dstIP),swap16(res->totalLength),(swap16(res->flagsAndOffset)
// >> 3));
ether_frame_provider_send(dest_mac, 0x0800, dat1,
size - i * (MTU - sizeof(struct IPV4Message)) +
sizeof(struct IPV4Message));
} else {
res->totalLength = swap16(MTU);
res->flagsAndOffset = (offset << IP_OFFSET) | (1 << IP_MF);
res->flagsAndOffset = swap16(res->flagsAndOffset);
res->checkSum = 0;
res->checkSum = CheckSum((uint16_t *)dat, sizeof(struct IPV4Message));
memcpy((void *)dat1, (void *)res, sizeof(struct IPV4Message));
memcpy((void *)(dat1 + sizeof(struct IPV4Message)),
(void *)(data + i * (MTU - sizeof(struct IPV4Message))),
MTU - sizeof(struct IPV4Message));
// printk("ip:%08x,%08x
// size:%d\nMF:1\noffset:%d\n",swap32(res->srcIP),swap32(res->dstIP),swap16(res->totalLength),(swap16(res->flagsAndOffset)
// >> 3));
ether_frame_provider_send(dest_mac, 0x0800, dat1, MTU);
}
offset += (MTU - sizeof(struct IPV4Message)) / 8;
}
kfree((void *)dat1);
}
kfree(dat);
ident++;
return;
}
uint16_t CheckSum(uint16_t *data, uint32_t size) {
uint32_t tmp = 0;
for (int i = 0; i < size / 2; i++) {
tmp += ((data[i] & 0xff00) >> 8) | ((data[i] & 0x00ff) << 8);
}
if (size % 2)
tmp += ((uint16_t)((char *)data)[size - 1]) << 8;
while (tmp & 0xffff0000)
tmp = (tmp & 0xffff) + (tmp >> 16);
return ((~tmp & 0xff00) >> 8) | ((~tmp & 0x00ff) << 8);
}
uint32_t IP2UINT32_T(uint8_t *ip) {
uint8_t ip0, ip1, ip2, ip3;
ip0 = strtol(ip, '.', 10);
uint8_t t = ip0;
while (t >= 10) {
t /= 10;
ip++;
}
ip1 = strtol(ip + 2, '.', 10);
t = ip1;
while (t >= 10) {
t /= 10;
ip++;
}
ip2 = strtol(ip + 4, '.', 10);
t = ip2;
while (t >= 10) {
t /= 10;
ip++;
}
ip3 = strtol(ip + 6, NULL, 10);
return (uint32_t)((ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3);
}