Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
tcp.c
Go to the documentation of this file.
1#include "tcp.h"
2#include "libk/serial.h"
3#include "net/ip_type.h"
4#include "net/ipv4.h"
5#include "net/netbuff.h"
6#include "net/netdev.h"
7#include "net/netutils.h"
8#include <hal/rand/rand.h>
9#include <str.h>
10
11#define FLAG_FIN 0x01
12#define FLAG_SYN 0x02
13#define FLAG_RST 0x04
14#define FLAG_PSH 0x08
15#define FLAG_ACK 0x10
16#define FLAG_URG 0x20
17
18void handle_tcp(netdev_t* dev, struct ipv4_header* ip, uint8_t mac_dst[6]) {
19 uint8_t ihl = ip->version_ihl & 0x0F;
20 uint16_t ip_hdr_len = ihl * 4;
21
22 uint16_t total_len = vxNtohs(ip->total_length);
23 struct tcp_header* tcp =
24 (struct tcp_header*) ((uint8_t*) ip + ip_hdr_len);
25
26 uint8_t tcp_hdr_len = ((tcp->offset >> 4) & 0x0F) * 4;
27
28 // validasi
29 if (tcp_hdr_len < 20 || total_len < ip_hdr_len + tcp_hdr_len)
30 return;
31
32 // handle
33 auto flags = tcp->flags;
34 auto syn = flags & FLAG_SYN;
35 auto ack = flags & FLAG_ACK;
36 auto fin = flags & FLAG_FIN;
37
38 tcp_options_t client_opts;
39 parse_tcp_options(tcp, &client_opts);
40
41 if (syn && !ack) {
42 // LOG2_INFO("TCP", "Syn Received");
43
44 send_command(dev, ip, tcp, &client_opts, FLAG_SYN | FLAG_ACK,
45 mac_dst);
46 }
47
48 if (ack && !syn) {
49 uint8_t len_ = ((tcp->offset >> 4) & 0x0F) * 4;
50 uint16_t data_len = total_len - ip_hdr_len - len_;
51 uint8_t* payload = (uint8_t*) tcp + len_;
52
53 if (data_len > 0 && tcp->flags & FLAG_PSH) {
54 // LOG2_INFO("TCP", "Data diterima: %d bytes", data_len);
55
56 if (data_len >= 4
57 && strncmp((char*) payload, "GET ", 4) == 0) {
58 // LOG2_INFO("TCP", "http request");
59
60 // print payload
61 // serial2_printf("%s", payload);
62 // 2. Kirim HTTP response
63 char* http_resp = "HTTP/1.1 200 OK\r\n"
64 "Content-Length: 13\r\n"
65 "Connection: close\r\n"
66 "\r\n"
67 "Hello, World!";
68 send_tcp_data(dev, ip, tcp,
69 (uint8_t*) http_resp, 71,
70 mac_dst);
71 }
72 } else if (fin) {
73 // ACK untuk FIN client
74 // send_tcp_ack(dev, ip, tcp, mac_dst);
75 send_command(dev, ip, tcp, &client_opts, FLAG_ACK,
76 mac_dst);
77 }
78 }
79}
80
81void send_command(netdev_t* dev, struct ipv4_header* ip, struct tcp_header* tcp,
82 tcp_options_t* opt, uint8_t flags, uint8_t mac_dst[6]) {
83
84 uint8_t opt_buf[80];
85 uint8_t opt_len = build_synack_options(dev, opt_buf, opt);
86
87 auto nb = create_netbuff();
88
89 auto reply_len = sizeof(struct tcp_header) + opt_len;
90 struct tcp_header* tcp_reply =
91 (struct tcp_header*) netbuff_push(nb, reply_len);
92
93 if (!tcp_reply) {
94 free_netbuff(nb);
95 return;
96 }
97
98 uint8_t* opt_ptr = (uint8_t*) (tcp_reply + 1);
99 memcopy(opt_ptr, opt_buf, opt_len);
100 tcp_reply->offset = (uint8_t) ((5 + opt_len / 4) << 4);
101
102 tcp_reply->source_port = tcp->destination_port;
103 tcp_reply->destination_port = tcp->source_port;
104 tcp_reply->sequence = vxHtonl(vxRand());
105 tcp_reply->acknowledgment = vxHtonl(vxNtohl(tcp->sequence) + 1);
106
107 tcp_reply->flags = flags;
108 tcp_reply->window = vxHtons(65535);
109
110 tcp_reply->checksum = 0;
111
112 // pseudo ip
113 struct __attribute__((packed)) {
118 uint16_t tcp_length;
119 } pseudo = {0};
120
121 pseudo.src_ip = ip->dst_ip;
122 pseudo.dst_ip = ip->src_ip;
123 pseudo.protocol = TCP_PROTOCOL;
124 pseudo.tcp_length = vxHtons((uint16_t) reply_len);
125
126 uint32_t sum = 0;
127 sum = checksum16_raw((uint16_t*) (void*) &pseudo, sizeof(pseudo));
128 sum += checksum16_raw((uint16_t*) (void*) tcp_reply, reply_len);
129
130 while (sum >> 16)
131 sum = (sum & 0xFFFF) + (sum >> 16);
132
133 tcp_reply->checksum = (uint16_t) (~sum);
134
135 ipv4_send(dev, nb, ip->src_ip, TCP_PROTOCOL, mac_dst);
136 free_netbuff(nb);
137}
138
139void send_tcp_data(netdev_t* dev, struct ipv4_header* ip,
140 struct tcp_header* tcp, uint8_t* data, size_t len,
141 uint8_t mac_dst[6]) {
142
143 // 1. Hitung panjang data yang masuk (HTTP GET) untuk menentukan nilai ACK balasan
144 uint8_t ihl = ip->version_ihl & 0x0F;
145 uint16_t ip_hdr_len = ihl * 4;
146 uint16_t ip_total_len = vxNtohs(ip->total_length);
147 uint8_t tcp_hdr_len_in = ((tcp->offset >> 4) & 0x0F) * 4;
148 uint16_t incoming_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len_in;
149
150 uint16_t total_tcp_len = (uint16_t) (sizeof(struct tcp_header) + len);
151
152 auto nb = create_netbuff();
153 // 3. Salin data (payload HTTP) tepat setelah TCP Header
154 uint8_t* payload_ptr = (uint8_t*) netbuff_put(nb, len);
155 memcopy(payload_ptr, data, len);
156
157 struct tcp_header* tcp_reply = (struct tcp_header*) netbuff_push(
158 nb, sizeof(struct tcp_header));
159
160 if (!tcp_reply) {
161 free_netbuff(nb);
162 return;
163 }
164
165 tcp_reply->offset = (5 << 4); // 20 bytes
166
167 tcp_reply->source_port = tcp->destination_port;
168 tcp_reply->destination_port = tcp->source_port;
169
170 // ACK yang diminta oleh klien
171 tcp_reply->sequence = tcp->acknowledgment;
172
173 //SEQ klien + panjang data (GET request) yang kita terima
174 uint32_t seq_in = vxNtohl(tcp->sequence);
175 tcp_reply->acknowledgment = vxHtonl(seq_in + incoming_data_len);
176
177 tcp_reply->flags =
179 | FLAG_PSH; // PSH (Push) memberitahu OS klien untuk segera membaca data
180 tcp_reply->window = vxHtons(65535);
181 tcp_reply->checksum = 0;
182
183 // 5. Buat Pseudo IP untuk Checksum
184 struct __attribute__((packed)) {
189 uint16_t tcp_length;
190 } pseudo = {0};
191
192 pseudo.src_ip = ip->dst_ip;
193 pseudo.dst_ip = ip->src_ip;
194 pseudo.protocol = TCP_PROTOCOL;
195 pseudo.tcp_length = vxHtons((uint16_t) total_tcp_len);
196
197 // 6. Hitung Checksum secara sekuensial (Mendukung data berukuran ganjil)
198 uint32_t sum = 0;
199 sum = checksum16_raw((uint16_t*) (void*) &pseudo, sizeof(pseudo));
200 sum += checksum16_raw((uint16_t*) (void*) tcp_reply,
201 sizeof(struct tcp_header));
202 sum += checksum16_raw((uint16_t*) (void*) payload_ptr, len);
203
204 while (sum >> 16)
205 sum = (sum & 0xFFFF) + (sum >> 16);
206
207 tcp_reply->checksum = (uint16_t) (~sum);
208
209 // 7. Kirim paket
210 ipv4_send(dev, nb, ip->src_ip, TCP_PROTOCOL, mac_dst);
211 free_netbuff(nb);
212}
213
214void parse_tcp_options(struct tcp_header* tcp, tcp_options_t* out) {
215 memset(out, 0, sizeof(*out));
216 out->mss = 536; // default RFC 793
217
218 uint8_t* opt = (uint8_t*) (tcp + 1);
219 uint8_t hdr_len = ((tcp->offset >> 4) & 0x0F) * 4;
220 uint8_t* end = (uint8_t*) tcp + hdr_len;
221
222 while (opt < end) {
223 switch (*opt) {
224 case 0:
225 return; // End of options
226 case 1:
227 opt++;
228 continue; // NOP
229
230 case 2: // MSS
231 if (opt[1] == 4)
232 out->mss = (uint16_t) (opt[2] << 8) | opt[3];
233 opt += opt[1];
234 break;
235
236 case 3: // Window Scale
237 if (opt[1] == 3)
238 out->has_wscale = 1;
239 out->wscale = opt[2];
240 opt += opt[1];
241 break;
242
243 case 4: // SACK Permitted
244 out->sack_permitted = 1;
245 opt += opt[1];
246 break;
247
248 case 8: // Timestamp
249 if (opt[1] == 10) {
250 out->has_timestamp = 1;
251 out->ts_val = ((uint32_t) opt[2] << 24)
252 | ((uint32_t) opt[3] << 16)
253 | ((uint32_t) opt[4] << 8)
254 | opt[5];
255 out->ts_ecr = ((uint32_t) opt[6] << 24)
256 | ((uint32_t) opt[7] << 16)
257 | ((uint32_t) opt[8] << 8)
258 | opt[9];
259 }
260 opt += opt[1];
261 break;
262
263 default:
264 if (opt[1] == 0)
265 return; // corrupt, stop
266 opt += opt[1];
267 break;
268 }
269 }
270}
271
274 uint8_t* p = buf;
275
276 // 1. MSS (4 bytes)
277 uint16_t our_mss = dev->mtu - sizeof(struct ipv4_header)
278 - sizeof(struct tcp_header);
279 uint16_t mss =
280 (client_opts->mss < our_mss) ? client_opts->mss : our_mss;
281 *p++ = 2;
282 *p++ = 4;
283 *p++ = (mss >> 8) & 0xFF;
284 *p++ = mss & 0xFF;
285 *p++ = 1; // NOP
286
287 // 2. SACK Permitted (2 bytes)
288 // if (client_opts->sack_permitted) {
289 // *p++ = 4;
290 // *p++ = 2;
291 // }
292
293 // timestamp, butuh RTC
294 // if (client_opts->has_timestamp) {
295 // // Tambahkan NOP sampai posisi saat ini genap kelipatan 4
296 // while ((p - buf) % 4 != 0)
297 // *p++ = 1; // NOP
298
299 // *p++ = 8;
300 // *p++ = 10;
301 // uint32_t now =
302 // 1000; // Berikan nilai sembarang non-zero untuk SYN-ACK pertama
303
304 // *p++ = (now >> 24) & 0xFF;
305 // *p++ = (now >> 16) & 0xFF;
306 // *p++ = (now >> 8) & 0xFF;
307 // *p++ = now & 0xFF;
308 // *p++ = (client_opts->ts_val >> 24) & 0xFF;
309 // *p++ = (client_opts->ts_val >> 16) & 0xFF;
310 // *p++ = (client_opts->ts_val >> 8) & 0xFF;
311 // *p++ = client_opts->ts_val & 0xFF;
312 // }
313
314 // 4. Window Scale (3 bytes)
315 // if (client_opts->has_wscale) { // Gunakan boolean flag di sini!
316 // *p++ = 1; // 1 NOP sebelum WScale agar total opsi menjadi genap 4 byte
317 // *p++ = 3;
318 // *p++ = 3;
319 // *p++ = 7; // Skala kita (misal: 7)
320 // }
321
322 // 5. Padding di akhir memastikan total option length habis dibagi 4
323 // while ((p - buf) % 4 != 0)
324 // *p++ = 1; // NOP
325
326 return (uint8_t) (p - buf);
327}
struct fs_data data
Definition filesystem.h:1
uint16_t flags
Definition thread.h:5
#define TCP_PROTOCOL
Definition ip_type.h:7
void ipv4_send(netdev_t *dev, struct netbuff *nb, uint32_t dst_ip, uint8_t protocol, uint8_t mac_dest[6])
Definition ipv4.c:32
uint32_t dst_ip
Definition ipv4.h:9
uint32_t src_ip
Definition ipv4.h:8
uint8_t protocol
Definition ipv4.h:6
void free_netbuff(struct netbuff *netbuff)
Definition netbuff.c:56
void * netbuff_put(struct netbuff *nb, size_t len)
Definition netbuff.c:42
void * netbuff_push(struct netbuff *nb, size_t len)
Definition netbuff.c:50
struct netbuff * create_netbuff()
Definition netbuff.c:19
struct netdev netdev_t
Definition netdev.h:19
uint32_t checksum16_raw(const uint16_t *data, size_t length)
Definition netutils.c:49
static uint16_t vxNtohs(uint16_t netshort)
Definition netutils.h:10
static uint32_t vxNtohl(uint32_t netlong)
Definition netutils.h:20
static uint32_t vxHtonl(uint32_t value)
Definition netutils.h:15
static uint16_t vxHtons(uint16_t value)
Definition netutils.h:6
size_t len
Definition oct2bin.h:7
uint32_t vxRand()
Definition rand.c:18
int strncmp(const char *s1, const char *s2, size_t n)
void memset(void *ptr, int value, size_t num)
void memcopy(void *dest, void *src, size_t size)
uint32_t zero
Definition interrupt.h:37
uint16_t total_length
Definition ipv4.h:11
uint32_t src_ip
Definition ipv4.h:17
uint8_t version_ihl
Definition ipv4.h:9
uint32_t dst_ip
Definition ipv4.h:18
uint16_t mtu
Definition netdev.h:36
uint8_t wscale
Definition tcp.h:27
uint8_t has_wscale
Definition tcp.h:26
uint32_t ts_ecr
Definition tcp.h:31
uint8_t has_timestamp
Definition tcp.h:29
uint8_t sack_permitted
Definition tcp.h:28
uint16_t mss
Definition tcp.h:25
uint32_t ts_val
Definition tcp.h:30
void handle_tcp(netdev_t *dev, struct ipv4_header *ip, uint8_t mac_dst[6])
Definition tcp.c:18
void send_command(netdev_t *dev, struct ipv4_header *ip, struct tcp_header *tcp, tcp_options_t *opt, uint8_t flags, uint8_t mac_dst[6])
Definition tcp.c:81
#define FLAG_PSH
Definition tcp.c:14
#define FLAG_FIN
Definition tcp.c:11
void send_tcp_data(netdev_t *dev, struct ipv4_header *ip, struct tcp_header *tcp, uint8_t *data, size_t len, uint8_t mac_dst[6])
Definition tcp.c:139
#define FLAG_ACK
Definition tcp.c:15
#define FLAG_SYN
Definition tcp.c:12
uint8_t build_synack_options(netdev_t *dev, uint8_t *buf, tcp_options_t *client_opts)
Definition tcp.c:273
void parse_tcp_options(struct tcp_header *tcp, tcp_options_t *out)
Definition tcp.c:214
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
unsigned char uint8_t
Definition type.h:7