im and openchess build.sh clean action fixed - it delete content of bin directory...
[ZeXOS.git] / kernel / core / net / tcp.c
blob112d0d4d2ac591c4dc20920d3fffcb50f038a08e
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <system.h>
21 #include <string.h>
22 #include <dev.h>
23 #include <net/eth.h>
24 #include <net/net.h>
25 #include <net/if.h>
26 #include <net/packet.h>
27 #include <net/ip.h>
28 #include <net/tcp.h>
29 #include <net/socket.h>
30 #include <mutex.h>
32 /* Mutex for socket function */
33 MUTEX_CREATE (mutex_tcp_accept);
34 MUTEX_CREATE (mutex_tcp_read_cache);
36 proto_tcp_conn_t proto_tcp_conn_list;
37 proto_tcp_backlog_t proto_tcp_backlog_list;
39 extern netif_t netif_list;
41 static net_port proto_tcp_client_port;
42 static unsigned short proto_tcp_dup;
43 static unsigned proto_tcp_seq;
44 static unsigned proto_tcp_fd;
46 /* prototype */
47 proto_tcp_conn_t *net_proto_tcp_conn_check (net_ipv4 ip_source, net_port port_source, net_ipv4 ip_dest, net_port port_dest, unsigned char *ret);
48 int net_proto_tcp_conn_add ();
49 int net_proto_tcp_conn_set (proto_tcp_conn_t *conn, netif_t *eth, net_port port_source, net_ipv4 ip_dest, net_port port_dest);
50 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest);
51 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
52 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len);
53 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
54 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len);
55 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len);
56 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
57 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
58 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn);
59 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn);
60 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd);
61 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
62 int net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
64 /** TCP protocol
65 * User-friendly socket functions
67 int net_proto_tcp_socket ()
69 return net_proto_tcp_conn_add ();
72 extern unsigned long timer_ticks;
73 int net_proto_tcp_connect (int fd, sockaddr_in *addr)
75 int ret = -1;
77 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
79 if (!conn)
80 return -1;
82 netif_t *netif;
83 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
84 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
86 unsigned long stime = timer_ticks;
88 /* blocking mode */
89 if (!(conn->flags & O_NONBLOCK)) {
90 if (!ret)
91 return -1;
93 while (1) {
94 schedule ();
96 /* timeout for 3s */
97 if ((stime+3000) < timer_ticks)
98 return -1;
100 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
101 break;
103 /* when connection cant be accepted succefully first time, try it again */
104 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
105 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
106 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
109 } else
110 /* non-blocking mode */
111 return -1;
113 ret = 0;
116 return ret;
119 int net_proto_tcp_send (int fd, char *msg, unsigned size)
121 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
123 if (!conn)
124 return -1;
126 int ret = net_proto_tcp_write_data (conn, msg, size);
128 if (ret) {
129 unsigned long stime = timer_ticks;
131 /* blocking mode */
132 if (!(conn->flags & O_NONBLOCK)) {
133 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
134 /* timeout 350ms */
135 if ((stime+350) < timer_ticks)
136 return -1;
138 schedule ();
140 } else {
142 /* non-blocking mode */
143 /* TODO: ? */
144 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
145 /* timeout 100ms */
146 if ((stime+100) < timer_ticks)
147 return size;
152 return size;
155 int net_proto_tcp_recv (int fd, char *msg, unsigned size)
157 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
159 if (!conn)
160 return -3;
162 int ret = 0;
164 //kprintf ("recv () - %d\n", fd);
166 /* blocking mode */
167 if (!(conn->flags & O_NONBLOCK)) {
168 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
169 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
170 if (net_proto_tcp_conn_del (conn));
171 return -1;
174 schedule ();
176 } else {
177 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
178 if (net_proto_tcp_conn_del (conn));
179 return -1;
182 if (!conn->len)
183 return 0;
186 if ((conn->len-conn->offset) > size) {
187 memcpy (msg, conn->data+conn->offset, size);
188 //printf ("msg: %d %d\n", conn->offset, size);
189 conn->offset += size;
191 ret = size;
192 } else {
193 ret = conn->len;
195 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
196 //printf ("msg2: %d %d\n", conn->offset, size);
197 conn->len = 0;
198 conn->offset = 0;
200 kfree (conn->data);
203 //kprintf ("recv () - %d -- DATA: %d\n", fd, ret);
205 return ret;
208 int net_proto_tcp_close (int fd)
210 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
212 if (!conn)
213 return -1;
215 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
216 return 0;
218 int ret = net_proto_tcp_conn_close (conn);
220 return ret;
223 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
225 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
227 if (!conn)
228 return -1;
230 switch (cmd) {
231 case F_GETFL:
232 return conn->flags;
233 case F_SETFL:
234 conn->flags = arg;
235 return 0;
238 return -1;
241 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
243 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
245 if (!conn)
246 return -1;
248 netif_t *netif;
249 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
250 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
251 conn->bind = 1;
252 return 0;
255 return -1;
258 int net_proto_tcp_listen (int fd, int backlog)
260 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
262 if (!conn)
263 return -1;
265 return 0;
268 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
270 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
272 if (!conn)
273 return -1;
275 unsigned i = 0;
277 proto_tcp_backlog_t *backlog = 0;
279 /* blocking mode */
280 if (!(conn->flags & O_NONBLOCK)) {
281 while (!i) {
282 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
283 if (backlog->conn == conn) {
284 i = 1;
285 break;
289 schedule ();
291 } else {
292 /* non-blocking mode */
293 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
294 if (backlog->conn == conn) {
295 i = 1;
296 break;
301 //printf ("accept ()\n");
303 if (!i)
304 return -1;
306 net_ipv4 ip = backlog->ip;
307 net_port port = backlog->port;
308 unsigned seq = backlog->seq;
310 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
312 /* remove from queue accepted connection */
313 backlog->next->prev = backlog->prev;
314 backlog->prev->next = backlog->next;
316 kfree (backlog);
318 if (ret < 1)
319 return ret;
321 int fd_new = net_proto_tcp_conn_add ();
323 if (!fd_new)
324 return 0;
326 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new);
328 if (!conn_new)
329 return -1;
331 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
333 conn_new->ip_dest = ip;
335 addr->sin_addr = ip;
336 addr->sin_port = port;
337 addr->sin_family = AF_INET;
339 return fd_new;
342 /** TCP protocol
343 * Hardcore code - syn, ack, psh, fin, etc :P
345 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
347 proto_tcp_t *tcp = (proto_tcp_t *) buf;
349 unsigned char ret = 0;
351 /* First check ip address and ports, that we want this data */
352 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
354 if (!conn && ret == 0)
355 return 1;
357 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
359 /* connection from client before accept () */
360 if (ret == 1) {
361 /* client want connect to our server */
362 if (tcp->flags == 0x02) {
363 mutex_lock (&mutex_tcp_accept);
365 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
367 mutex_unlock (&mutex_tcp_accept);
369 return ret;
372 return 1;
375 unsigned data_cache = 0;
377 /* data received */
378 if (tcp->flags & 0x08) {
379 /* needed for calculate real offset from 4bit number */
380 unsigned offset = tcp->data_offset * 4;
382 /* now calculate accurate length of tcp _data_ */
383 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
384 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
385 //mutex_lock (&mutex_tcp_read_cache);
386 net_proto_tcp_read_cache (conn, buf+offset, size);
387 //mutex_unlock (&mutex_tcp_read_cache);
388 /* send ack */
389 net_proto_tcp_read_ok (conn, ip, tcp, size);
391 data_cache = 1;
394 /* sended data was delivered succefully */
395 if (tcp->flags & 0x10) {
396 /* HACK: It is interesting, that no push flag, and there could be some data to read */
398 /* needed for calculate real offset from 4bit number */
399 unsigned offset = tcp->data_offset * 4;
401 /* now calculate accurate length of tcp _data_ */
402 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
404 /* there are data for read */
405 if (size) {
406 /* data was cached, so no need cache it again */
407 if (!data_cache) {
408 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
409 mutex_lock (&mutex_tcp_read_cache);
410 net_proto_tcp_read_cache (conn, buf+offset, size);
411 mutex_unlock (&mutex_tcp_read_cache);
412 /* send ack */
413 net_proto_tcp_read_ok (conn, ip, tcp, size);
415 } else {
416 /* when data are'nt available, lets normal work - acknowledgement */
417 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
418 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
419 net_proto_tcp_write_data_ok (conn, ip, tcp);
420 } else
421 net_proto_tcp_write_data_ok (conn, ip, tcp);
425 /* connection estabilish respond */
426 if (tcp->flags == 0x12) {
427 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
430 /* another side close connection */
431 if (tcp->flags & 0x01) {
432 DPRINT ("TCP -> fd %d connection closed by remote host\n", conn->fd);
433 net_proto_tcp_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
436 /* another side close connection */
437 if (tcp->flags & 0x04) {
438 DPRINT ("TCP -> fd %d connection reseted by peer\n", conn->fd);
439 net_proto_tcp_conn_disconnected (conn, ip, tcp);
442 return 1;
445 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
447 if (!data || !conn || !len)
448 return 0;
450 if (!conn->len) {
451 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
453 memcpy (conn->data, data, len);
454 } else {
455 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
457 if (!newdata)
458 return 0;
460 memcpy (newdata, conn->data, conn->len);
461 memcpy (newdata+conn->len, data, len);
463 kfree (conn->data);
465 conn->data = newdata;
468 if (!conn->data)
469 return -1;
471 //kprintf ("DATA: %d - #'%s'#\n", len, data);
473 conn->len += len;
475 conn->data[conn->len] = '\0';
477 return conn->len;
480 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
482 if (!ip_old || !tcp_old || !conn)
483 return 0;
485 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
487 if (!tcp)
488 return 0;
490 tcp->port_source = conn->port_source; // increase client port too
491 tcp->port_dest = conn->port_dest;
493 tcp->seq = tcp_old->ack;
495 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
496 it returns 10 10 10 08, no 10 10 11 08 */
497 unsigned seq = swap32 (tcp_old->seq);
498 seq += len;
500 tcp->ack = swap32 (seq);
502 tcp->res = 0;
503 tcp->data_offset = 5;
504 tcp->flags = 0x10;
505 tcp->window = tcp_old->window + swap16 (64);
506 tcp->checksum = 0;
508 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
510 /*if (proto_tcp_dup == tcp_old->checksum) {
511 printf ("Duplicated packet :)");
512 timer_wait (150);
515 if (ret) {
516 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
518 conn->seq = tcp->ack;
519 conn->ack = tcp->seq;
521 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
523 proto_tcp_dup = tcp_old->checksum;
525 conn->cross = 1;
528 kfree (tcp);
530 return ret;
533 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
535 if (!eth || !tcp)
536 return 0;
538 if (len)
539 if (!data)
540 return 0;
542 mac_addr_t mac_dest;
543 unsigned get = arp_cache_get (dest, &mac_dest);
545 if (!get) {
546 arp_send_request (eth, dest);
548 unsigned i = 0;
549 /* 100ms for waiting on ARP reply */
550 while (i < 100) {
551 get = arp_cache_get (dest, &mac_dest);
553 if (get)
554 break;
556 /* TODO: make better waiting for ARP reply */
557 timer_wait (1);
559 schedule ();
561 i ++;
564 if (!get)
565 return 0;
568 /* packet header */
569 packet_t *packet = (packet_t *) kmalloc (sizeof (packet_t));
571 if (!packet)
572 return 0;
574 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
575 memcpy (&packet->mac_dest, mac_dest, 6);
576 packet->type = NET_PACKET_TYPE_IPV4;
578 /* ip layer */
579 proto_ip_t *ip = (proto_ip_t *) kmalloc (sizeof (proto_ip_t));
581 if (!ip)
582 return 0;
584 /* there are some fixed values - yeah it is horrible */
585 ip->ver = 4;
586 ip->head_len = 5;
588 ip->flags = 0;
589 ip->frag = 0;
590 ip->ttl = 64;
591 ip->checksum = 0;
592 ip->proto = NET_PROTO_IP_TYPE_TCP;
593 ip->ip_source = eth->ip;
594 ip->ip_dest = dest;
596 unsigned l = (tcp->data_offset*4);
598 /* calculate total length of packet (tcp/ip) */
599 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
601 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
603 if (!buf_tcp)
604 return 0;
606 memcpy (buf_tcp, (char *) tcp, l);
608 if (len)
609 memcpy (buf_tcp+l, data, len);
611 buf_tcp[l+len] = '\0';
613 /* calculate checksum and put it to tcp header */
614 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
616 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
618 /* send tcp header+data to ip layer */
619 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
621 kfree (buf_tcp);
622 kfree (ip);
623 kfree (packet);
625 return ret;
628 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
630 if (!conn || !len || !data)
631 return 0;
633 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
635 if (!tcp)
636 return 0;
638 tcp->port_source = conn->port_source;
639 tcp->port_dest = conn->port_dest;
641 unsigned seq = swap32 (proto_tcp_seq);
642 seq ++;
644 //tcp->ack = swap32 (seq);
646 proto_tcp_seq = swap32 (seq);
648 if (!conn->cross) {
649 tcp->seq = conn->seq;
650 tcp->ack = conn->ack;
651 } else {
652 tcp->seq = conn->ack;
653 tcp->ack = conn->seq;
655 conn->cross = 0;
658 //printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp_seq);
660 tcp->res = 0;
661 tcp->data_offset = 5;
662 tcp->flags = 0x18;
663 tcp->window = swap16 (32768);
664 tcp->checksum = 0;
666 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
668 kfree (tcp);
670 if (ret)
671 conn->state = PROTO_TCP_CONN_STATE_WAIT;
673 return ret;
676 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
678 if (!ip_old || !tcp_old || !conn)
679 return 0;
681 /* cross - because we change now sides :) */
682 conn->seq = tcp_old->ack;
683 conn->ack = tcp_old->seq;
685 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
687 conn->state = PROTO_TCP_CONN_STATE_READY;
689 return 1;
692 /* try connect to server */
693 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
695 if (!conn)
696 return 0;
698 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
700 if (!tcp)
701 return 0;
703 tcp->port_source = swap16 (proto_tcp_client_port); // increase client port too
704 tcp->port_dest = port_dest;
706 /* setup new connection */
707 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
709 tcp->seq = conn->seq;
710 tcp->ack = conn->ack;
712 tcp->res = 0;
713 tcp->data_offset = 5;
714 tcp->flags = 0x02;
715 tcp->window = swap16 (32792);
716 tcp->checksum = 0;
718 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
720 kfree (tcp);
722 if (!ret) {
723 net_proto_tcp_conn_del (conn);
724 return 0;
727 return 1;
730 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
732 if (!ip_old || !tcp_old || !conn)
733 return 0;
735 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
737 if (!tcp)
738 return 0;
740 tcp->port_source = conn->port_source; // increase client port too
741 tcp->port_dest = conn->port_dest;
743 tcp->seq = tcp_old->ack;
744 tcp->ack = tcp_old->seq + swap32 (1);
746 tcp->res = 0;
747 tcp->data_offset = 5;
748 tcp->flags = 0x10;
749 tcp->window = tcp_old->window + swap16 (64);
750 tcp->checksum = 0;
752 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
754 if (ret) {
755 conn->seq = tcp->seq;
756 conn->ack = tcp->ack;
757 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
760 DPRINT ("TCP -> fd %ï connected to server succefully\n", conn->fd);
762 kfree (tcp);
764 return ret;
767 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
769 if (!ip_old || !tcp_old || !conn)
770 return 0;
772 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
773 return net_proto_tcp_conn_del (conn);
775 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
777 if (!tcp)
778 return 0;
780 tcp->port_source = conn->port_source; // increase client port too
781 tcp->port_dest = conn->port_dest;
783 tcp->seq = tcp_old->ack;
784 tcp->ack = tcp_old->seq + swap32 (1);
786 tcp->res = 0;
787 tcp->data_offset = 5;
788 tcp->flags = 0x10;
789 tcp->window = tcp_old->window + swap16 (64);
790 tcp->checksum = 0;
792 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
794 kfree (tcp);
796 if (ret)
797 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
798 else
799 return -1;
801 return ret;
804 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
806 if (!conn)
807 return 0;
809 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
811 if (!tcp)
812 return 0;
814 tcp->port_source = conn->port_source; // increase client port too
815 tcp->port_dest = conn->port_dest;
817 tcp->seq = conn->seq;
818 tcp->ack = conn->ack;
820 tcp->res = 0;
821 tcp->data_offset = 5;
822 tcp->flags = 0x11;
823 tcp->window = swap16 (32832);
824 tcp->checksum = 0;
826 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
828 kfree (tcp);
830 if (ret) {
831 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
834 return ret;
837 /* client wants to connect */
838 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
840 if (!conn)
841 return 0;
843 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
845 if (!tcp)
846 return 0;
848 tcp->port_source = conn->port_source;
849 tcp->port_dest = port;
851 tcp->seq = proto_tcp_seq ++;
852 tcp->ack = seq + swap32 (1);
854 tcp->res = 0;
855 tcp->data_offset = 5;
856 tcp->flags = 0x12;
857 tcp->window = swap16 (5816);
858 tcp->checksum = 0;
860 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
862 kfree (tcp);
864 if (ret)
865 conn->state = PROTO_TCP_CONN_STATE_READY;
866 else {
867 printf ("wtf ?\n");
868 return -1;
870 return 1;
873 /* Create new TCP connection */
874 int net_proto_tcp_conn_add ()
876 proto_tcp_conn_t *conn;
878 /* alloc and init context */
879 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
881 if (!conn)
882 return 0;
884 memset (conn, 0, sizeof (proto_tcp_conn_t));
886 conn->flags = 0;
887 conn->bind = 0;
889 conn->fd = proto_tcp_fd ++;
891 conn->cross = 0;
893 /* add into list */
894 conn->next = &proto_tcp_conn_list;
895 conn->prev = proto_tcp_conn_list.prev;
896 conn->prev->next = conn;
897 conn->next->prev = conn;
899 return conn->fd;
902 /* Setup new connection */
903 int net_proto_tcp_conn_set (proto_tcp_conn_t *conn, netif_t *eth, net_port port_source, net_ipv4 ip_dest, net_port port_dest)
905 if (!conn || !eth)
906 return 0;
908 conn->ip_source = eth->ip;
909 conn->ip_dest = ip_dest;
911 conn->port_source = port_source;
912 conn->port_dest = port_dest;
914 proto_tcp_seq += swap32 (1);
916 conn->seq = proto_tcp_seq ++;
917 conn->ack = 0;
919 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
921 conn->netif = eth;
923 conn->offset = 0;
924 conn->len = 0;
925 conn->data = 0;
927 return 1;
930 /* Delete existing connection from list */
931 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
933 if (!conn)
934 return 0;
936 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
938 if (conn->len)
939 kfree (conn->data);
941 conn->len = 0;
943 conn->next->prev = conn->prev;
944 conn->prev->next = conn->next;
946 kfree (conn);
948 return 1;
951 proto_tcp_conn_t *net_proto_tcp_conn_check (net_ipv4 ip_source, net_port port_source, net_ipv4 ip_dest, net_port port_dest, unsigned char *ret)
953 *ret = 0;
954 proto_tcp_conn_t *conn = NULL;
955 proto_tcp_conn_t *conn_ret = NULL;
956 //printf ("-------------------------\n");
957 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
958 /*printf ("-> ");
959 net_proto_ip_print (conn->ip_source);
960 printf (" / ");
961 net_proto_ip_print (ip_source);
962 printf ("\n2> ");
963 net_proto_ip_print (conn->ip_dest);
964 printf (" / ");
965 net_proto_ip_print (ip_dest);
966 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
967 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
969 if (conn->ip_source == ip_source && conn->port_source == port_source) {
970 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
971 *ret = 2;
972 return conn;
975 *ret = 1;
977 conn_ret = conn;
981 if (*ret == 1)
982 if (!conn_ret->bind) {
983 conn_ret = 0;
985 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
986 if (conn->bind) {
987 if (conn->ip_source == ip_source && conn->port_source == port_source)
988 conn_ret = conn;
993 return conn_ret;
996 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
998 proto_tcp_conn_t *conn = NULL;
999 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1000 if (conn->fd == fd)
1001 return conn;
1004 return 0;
1007 /* Create new TCP backlog stamp */
1008 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
1010 if (!conn)
1011 return 0;
1013 proto_tcp_backlog_t *backlog;
1015 /* alloc and init context */
1016 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
1018 if (!backlog)
1019 return 0;
1021 backlog->conn = conn;
1022 backlog->ip = ip;
1023 backlog->port = port;
1024 backlog->seq = seq;
1026 /* add into list */
1027 backlog->next = &proto_tcp_backlog_list;
1028 backlog->prev = proto_tcp_backlog_list.prev;
1029 backlog->prev->next = backlog;
1030 backlog->next->prev = backlog;
1032 return conn->fd;
1035 /* init of tcp protocol */
1036 unsigned init_net_proto_tcp ()
1038 proto_tcp_conn_list.next = &proto_tcp_conn_list;
1039 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
1041 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
1042 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
1044 /* base tcp client port, which is used for client's use */
1045 proto_tcp_client_port = 1024;
1046 proto_tcp_dup = 0x0;
1047 proto_tcp_seq = 0x1;
1048 proto_tcp_fd = 1024;
1050 return 1;