New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / kernel / core / net / tcp.c
blob5ddca1ed37292d28cebad7e70219d38fe64bf57f
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <system.h>
23 #include <string.h>
24 #include <dev.h>
25 #include <net/eth.h>
26 #include <net/net.h>
27 #include <net/if.h>
28 #include <net/packet.h>
29 #include <net/ip.h>
30 #include <net/tcp.h>
31 #include <net/socket.h>
32 #include <mutex.h>
33 #include <errno.h>
34 #include <fd.h>
36 /* Mutex for socket function */
37 MUTEX_CREATE (mutex_tcp_accept);
38 MUTEX_CREATE (mutex_tcp_read_cache);
40 proto_tcp_conn_t proto_tcp_conn_list;
41 proto_tcp_backlog_t proto_tcp_backlog_list;
43 extern netif_t netif_list;
45 static unsigned short proto_tcp_dup;
46 static unsigned proto_tcp_seq;
47 static proto_ip_t proto_ip_prealloc;
48 static proto_tcp_t proto_tcp_prealloc;
49 static packet_t packet_prealloc;
51 /* prototype */
52 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);
53 int net_proto_tcp_conn_add (fd_t *fd);
54 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);
55 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest);
56 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
57 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len);
58 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
59 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len);
60 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len);
61 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
62 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
63 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn);
64 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn);
65 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd);
66 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
67 int net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
69 /** TCP protocol
70 * User-friendly socket functions
72 int net_proto_tcp_socket (fd_t *fd)
74 return net_proto_tcp_conn_add (fd);
77 extern unsigned long timer_ticks;
78 int net_proto_tcp_connect (int fd, sockaddr_in *addr)
80 int ret = -1;
82 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
84 if (!conn)
85 return -1;
87 netif_t *netif;
88 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
89 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
91 unsigned long stime = timer_ticks;
93 /* blocking mode */
94 if (!(conn->flags & O_NONBLOCK)) {
95 if (!ret)
96 return -1;
98 for (;;) {
99 schedule ();
101 /* timeout for 8s */
102 if ((stime+8000) < timer_ticks)
103 return -1;
105 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
106 break;
108 /* when connection cant be accepted succefully first time, try it again */
109 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
110 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
111 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
114 } else
115 /* non-blocking mode */
116 return -1;
118 ret = 0;
121 return ret;
124 int net_proto_tcp_send (int fd, char *msg, unsigned size)
126 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
128 if (!conn)
129 return -1;
131 int ret = net_proto_tcp_write_data (conn, msg, size);
133 if (ret) {
134 unsigned long stime = timer_ticks;
136 /* blocking mode */
137 if (!(conn->flags & O_NONBLOCK)) {
138 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
139 /* timeout 350ms */
140 if ((stime+350) < timer_ticks)
141 return -1;
143 schedule ();
145 } else {
147 /* non-blocking mode */
148 /* TODO: ? */
149 #ifdef TEST
150 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
151 /* timeout 100ms */
152 if ((stime+100) < timer_ticks)
153 return size;
155 printf ("");
157 #endif
161 return size;
164 int net_proto_tcp_recv (int fd, char *msg, unsigned size)
166 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
168 if (!conn)
169 return -3;
171 int ret = 0;
173 //kprintf ("recv () - %d\n", fd);
175 /* blocking mode */
176 if (!(conn->flags & O_NONBLOCK)) {
177 unsigned long stime = timer_ticks;
179 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
180 if ((stime+10000) < timer_ticks)
181 return -1;
183 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
184 if (net_proto_tcp_conn_del (conn));
185 return -1;
188 schedule ();
190 } else {
191 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
192 if (net_proto_tcp_conn_del (conn));
193 return -1;
196 if (!conn->len)
197 return 0;
200 if ((conn->len-conn->offset) > size) {
201 memcpy (msg, conn->data+conn->offset, size);
202 //printf ("msg11: %d %d\n", conn->offset, size);
203 conn->offset += size;
205 ret = size;
206 } else {
207 ret = conn->len-conn->offset;
209 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
210 //printf ("msg22: %d %d %d\n", conn->offset, size, conn->len);
211 conn->len = 0;
212 conn->offset = 0;
214 kfree (conn->data);
217 //kprintf ("recv () - %d -- DATA: %d : %d\n", fd, ret, size);
219 return ret;
222 int net_proto_tcp_close (int fd)
224 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
226 if (!conn)
227 return -1;
229 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
230 return 0;
232 return net_proto_tcp_conn_close (conn);
235 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
237 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
239 if (!conn)
240 return -1;
242 switch (cmd) {
243 case F_GETFL:
244 return conn->flags;
245 case F_SETFL:
246 conn->flags = arg;
247 return 0;
250 return -1;
253 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
255 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
257 if (!conn)
258 return -1;
260 netif_t *netif;
261 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
262 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
263 conn->bind = 1;
264 return 0;
267 return -1;
270 int net_proto_tcp_listen (int fd, int backlog)
272 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
274 if (!conn)
275 return -1;
277 return 0;
280 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
282 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
284 if (!conn)
285 return -1;
287 unsigned i = 0;
289 proto_tcp_backlog_t *backlog = 0;
291 /* blocking mode */
292 if (!(conn->flags & O_NONBLOCK)) {
293 while (!i) {
294 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
295 if (backlog->conn == conn) {
296 i = 1;
297 break;
301 schedule ();
303 } else {
304 /* non-blocking mode */
305 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
306 if (backlog->conn == conn) {
307 i = 1;
308 break;
313 //printf ("accept ()\n");
315 if (!i)
316 return -1;
318 net_ipv4 ip = backlog->ip;
319 net_port port = backlog->port;
320 unsigned seq = backlog->seq;
322 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
324 /* remove from queue accepted connection */
325 backlog->next->prev = backlog->prev;
326 backlog->prev->next = backlog->next;
328 kfree (backlog);
330 if (ret < 1)
331 return ret;
333 fd_t *fd_new = fd_create (FD_SOCK);
335 if (!fd_new)
336 return 0;
338 net_proto_tcp_conn_add (fd_new);
340 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new->id);
342 if (!conn_new)
343 return -1;
345 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
347 conn_new->ip_dest = ip;
349 addr->sin_addr = ip;
350 addr->sin_port = port;
351 addr->sin_family = AF_INET;
353 return fd_new->id;
356 int net_proto_tcp_select (int readfd, int writefd, int exceptfd)
358 int fd = -1;
360 if (readfd)
361 fd = readfd;
362 else if (writefd)
363 fd = writefd;
364 else if (exceptfd)
365 fd = exceptfd;
367 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
369 if (!conn)
370 return -1;
372 /* check for incoming connections */
373 if (conn->bind) {
374 proto_tcp_backlog_t *backlog = 0;
376 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
377 if (backlog->conn == conn)
378 return 1;
381 return 0;
384 /* Is socket closed ? */
385 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
386 return 1;
388 /* Are some data available ? */
389 if (conn->len)
390 return 1;
392 return 0;
395 /** TCP protocol
396 * Hardcore code - syn, ack, psh, fin, etc :P
398 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
400 proto_tcp_t *tcp = (proto_tcp_t *) buf;
402 unsigned char ret = 0;
404 /* First check ip address and ports, that we want this data */
405 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
407 if (!conn && ret == 0)
408 return 1;
410 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
412 /* connection from client before accept () */
413 if (ret == 1) {
414 /* client want connect to our server */
415 if (tcp->flags == 0x02) {
416 mutex_lock (&mutex_tcp_accept);
418 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
420 mutex_unlock (&mutex_tcp_accept);
422 return ret;
425 return 1;
428 unsigned data_cache = 0;
430 /* data received */
431 if (tcp->flags & 0x08) {
432 /* needed for calculate real offset from 4bit number */
433 unsigned offset = tcp->data_offset * 4;
435 /* now calculate accurate length of tcp _data_ */
436 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
437 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
438 //mutex_lock (&mutex_tcp_read_cache);
439 net_proto_tcp_read_cache (conn, buf+offset, size);
440 //mutex_unlock (&mutex_tcp_read_cache);
441 /* send ack */
442 net_proto_tcp_read_ok (conn, ip, tcp, size);
444 data_cache = 1;
447 /* sended data was delivered succefully */
448 if (tcp->flags & 0x10) {
449 /* HACK: It is interesting, that no push flag, and there could be some data to read */
451 /* needed for calculate real offset from 4bit number */
452 unsigned offset = tcp->data_offset * 4;
454 /* now calculate accurate length of tcp _data_ */
455 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
457 /* there are data for read */
458 if (size) {
459 /* data was cached, so no need cache it again */
460 if (!data_cache) {
461 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
462 mutex_lock (&mutex_tcp_read_cache);
463 net_proto_tcp_read_cache (conn, buf+offset, size);
464 mutex_unlock (&mutex_tcp_read_cache);
465 /* send ack */
466 net_proto_tcp_read_ok (conn, ip, tcp, size);
468 } else {
469 /* when data are'nt available, lets normal work - acknowledgement */
470 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
471 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
472 net_proto_tcp_write_data_ok (conn, ip, tcp);
473 } else
474 net_proto_tcp_write_data_ok (conn, ip, tcp);
478 /* connection estabilish respond */
479 if (tcp->flags == 0x12) {
480 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
483 /* another side close connection */
484 if (tcp->flags & 0x01) {
485 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection closed by remote host", conn->fd);
486 net_proto_tcp_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
489 /* another side close connection */
490 if (tcp->flags & 0x04) {
491 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection reseted by peer", conn->fd);
492 net_proto_tcp_conn_disconnected (conn, ip, tcp);
495 return 1;
498 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
500 if (!data || !conn || !len)
501 return 0;
503 if (!conn->len) {
504 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
506 memcpy (conn->data, data, len);
507 } else {
508 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
510 if (!newdata)
511 return 0;
513 memcpy (newdata, conn->data, conn->len);
514 memcpy (newdata+conn->len, data, len);
516 kfree (conn->data);
518 conn->data = newdata;
521 if (!conn->data)
522 return -1;
524 //kprintf ("DATA: %d - #'%s'#\n", len, data);
526 conn->len += len;
528 conn->data[conn->len] = '\0';
530 return conn->len;
533 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
535 if (!ip_old || !tcp_old || !conn)
536 return 0;
538 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
540 if (!tcp)
541 return 0;
543 tcp->port_source = conn->port_source; // increase client port too
544 tcp->port_dest = conn->port_dest;
546 tcp->seq = tcp_old->ack;
548 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
549 it returns 10 10 10 08, no 10 10 11 08 */
550 unsigned seq = swap32 (tcp_old->seq);
551 seq += len;
553 tcp->ack = swap32 (seq);
555 tcp->res = 0;
556 tcp->data_offset = 5;
557 tcp->flags = 0x10;
558 tcp->window = tcp_old->window + swap16 (64);
559 tcp->checksum = 0;
561 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
563 /*if (proto_tcp_dup == tcp_old->checksum) {
564 printf ("Duplicated packet :)");
565 timer_wait (150);
568 if (ret) {
569 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
571 conn->seq = tcp->ack;
572 conn->ack = tcp->seq;
574 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
576 proto_tcp_dup = tcp_old->checksum;
578 conn->cross = 1;
581 kfree (tcp);
583 return ret;
586 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
588 if (!eth || !tcp)
589 return 0;
591 if (len)
592 if (!data)
593 return 0;
595 mac_addr_t mac_dest;
596 unsigned get = arp_cache_get (dest, &mac_dest);
598 if (!get) {
599 arp_send_request (eth, dest);
601 unsigned i = 0;
602 /* 100ms for waiting on ARP reply */
603 while (i < 100) {
604 get = arp_cache_get (dest, &mac_dest);
606 if (get)
607 break;
609 /* TODO: make better waiting for ARP reply */
610 timer_wait (1);
612 schedule ();
614 i ++;
617 if (!get)
618 return 0;
621 /* packet header */
622 packet_t *packet = &packet_prealloc;
624 if (!packet)
625 return 0;
627 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
628 memcpy (&packet->mac_dest, mac_dest, 6);
629 packet->type = NET_PACKET_TYPE_IPV4;
631 /* ip layer */
632 proto_ip_t *ip = &proto_ip_prealloc;
634 if (!ip)
635 return 0;
637 /* there are some fixed values - yeah it is horrible */
638 ip->ver = 4;
639 ip->head_len = 5;
641 ip->flags = 0;
642 ip->frag = 0;
643 ip->ttl = 64;
644 ip->checksum = 0;
645 ip->proto = NET_PROTO_IP_TYPE_TCP;
646 ip->ip_source = eth->ip;
647 ip->ip_dest = dest;
649 unsigned l = (tcp->data_offset*4);
651 /* calculate total length of packet (tcp/ip) */
652 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
654 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
656 if (!buf_tcp)
657 return 0;
659 memcpy (buf_tcp, (char *) tcp, l);
661 if (len)
662 memcpy (buf_tcp+l, data, len);
664 buf_tcp[l+len] = '\0';
666 /* calculate checksum and put it to tcp header */
667 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
669 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
671 /* send tcp header+data to ip layer */
672 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
674 kfree (buf_tcp);
676 return ret;
679 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
681 if (!conn || !len || !data)
682 return 0;
684 proto_tcp_t *tcp = &proto_tcp_prealloc;
686 if (!tcp)
687 return 0;
689 tcp->port_source = conn->port_source;
690 tcp->port_dest = conn->port_dest;
692 unsigned seq = swap32 (proto_tcp_seq);
693 seq ++;
695 //tcp->ack = swap32 (seq);
697 proto_tcp_seq = swap32 (seq);
699 if (!conn->cross) {
700 tcp->seq = conn->seq;
701 tcp->ack = conn->ack;
702 } else {
703 tcp->seq = conn->ack;
704 tcp->ack = conn->seq;
706 conn->cross = 0;
709 // printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp_seq);
711 tcp->res = 0;
712 tcp->data_offset = 5;
713 tcp->flags = 0x18;
714 tcp->window = swap16 (32768);
715 tcp->checksum = 0;
717 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
719 if (ret)
720 conn->state = PROTO_TCP_CONN_STATE_WAIT;
722 return ret;
725 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
727 if (!ip_old || !tcp_old || !conn)
728 return 0;
730 /* cross - because we change now sides :) */
731 conn->seq = tcp_old->ack;
732 conn->ack = tcp_old->seq;
734 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
736 conn->state = PROTO_TCP_CONN_STATE_READY;
738 return 1;
741 /* try connect to server */
742 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
744 if (!conn)
745 return 0;
747 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
749 if (!tcp)
750 return 0;
752 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
753 tcp->port_dest = port_dest;
755 /* setup new connection */
756 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
758 tcp->seq = conn->seq;
759 tcp->ack = conn->ack;
761 tcp->res = 0;
762 tcp->data_offset = 5;
763 tcp->flags = 0x02;
764 tcp->window = swap16 (32792);
765 tcp->checksum = 0;
767 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
769 kfree (tcp);
771 if (!ret) {
772 net_proto_tcp_conn_del (conn);
773 return 0;
776 return 1;
779 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
781 if (!ip_old || !tcp_old || !conn)
782 return 0;
784 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
786 if (!tcp)
787 return 0;
789 tcp->port_source = conn->port_source; // increase client port too
790 tcp->port_dest = conn->port_dest;
792 tcp->seq = tcp_old->ack;
793 tcp->ack = tcp_old->seq + swap32 (1);
795 tcp->res = 0;
796 tcp->data_offset = 5;
797 tcp->flags = 0x10;
798 tcp->window = tcp_old->window + swap16 (64);
799 tcp->checksum = 0;
801 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
803 if (ret) {
804 conn->seq = tcp->seq;
805 conn->ack = tcp->ack;
806 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
809 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connected to server succefully\n", conn->fd);
811 kfree (tcp);
813 return ret;
816 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
818 if (!ip_old || !tcp_old || !conn)
819 return 0;
821 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
822 return net_proto_tcp_conn_del (conn);
824 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
826 if (!tcp)
827 return 0;
829 tcp->port_source = conn->port_source; // increase client port too
830 tcp->port_dest = conn->port_dest;
832 tcp->seq = tcp_old->ack;
833 tcp->ack = tcp_old->seq + swap32 (1);
835 tcp->res = 0;
836 tcp->data_offset = 5;
837 tcp->flags = 0x10;
838 tcp->window = tcp_old->window + swap16 (64);
839 tcp->checksum = 0;
841 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
843 kfree (tcp);
845 if (ret)
846 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
847 else
848 return -1;
850 return ret;
853 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
855 return 0; /* FIXME: close () is faster then send () sometime :-B */
857 if (!conn)
858 return 0;
860 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
861 return 0;
863 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
865 if (!tcp)
866 return 0;
868 tcp->port_source = conn->port_source; // increase client port too
869 tcp->port_dest = conn->port_dest;
871 tcp->seq = conn->seq;
872 tcp->ack = conn->ack;
874 tcp->res = 0;
875 tcp->data_offset = 5;
876 tcp->flags = 0x11;
877 tcp->window = swap16 (32832);
878 tcp->checksum = 0;
880 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
882 kfree (tcp);
884 if (ret)
885 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
887 return ret;
890 /* client wants to connect */
891 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
893 if (!conn)
894 return 0;
896 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
898 if (!tcp)
899 return 0;
901 tcp->port_source = conn->port_source;
902 tcp->port_dest = port;
904 tcp->seq = proto_tcp_seq ++;
905 tcp->ack = seq + swap32 (1);
907 tcp->res = 0;
908 tcp->data_offset = 5;
909 tcp->flags = 0x12;
910 tcp->window = swap16 (5816);
911 tcp->checksum = 0;
913 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
915 kfree (tcp);
917 if (ret > 0)
918 conn->state = PROTO_TCP_CONN_STATE_READY;
919 else {
920 printf ("wtf ?\n");
921 return -1;
923 return 1;
926 /* Create new TCP connection */
927 int net_proto_tcp_conn_add (fd_t *fd)
929 proto_tcp_conn_t *conn;
931 /* alloc and init context */
932 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
934 if (!conn) {
935 errno_set (ENOMEM);
936 return -1;
939 memset (conn, 0, sizeof (proto_tcp_conn_t));
941 conn->flags = 0;
942 conn->bind = 0;
944 conn->fd = fd->id;
946 conn->cross = 0;
948 /* add into list */
949 conn->next = &proto_tcp_conn_list;
950 conn->prev = proto_tcp_conn_list.prev;
951 conn->prev->next = conn;
952 conn->next->prev = conn;
954 return 0;
957 /* Setup new connection */
958 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)
960 if (!conn || !eth)
961 return 0;
963 conn->ip_source = eth->ip;
964 conn->ip_dest = ip_dest;
966 conn->port_source = port_source;
967 conn->port_dest = port_dest;
969 proto_tcp_seq += swap32 (1);
971 conn->seq = proto_tcp_seq ++;
972 conn->ack = 0;
974 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
976 conn->netif = eth;
978 conn->offset = 0;
979 conn->len = 0;
980 conn->data = 0;
982 return 1;
985 /* Delete existing connection from list */
986 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
988 if (!conn)
989 return 0;
991 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
993 if (conn->len)
994 kfree (conn->data);
996 conn->len = 0;
998 conn->next->prev = conn->prev;
999 conn->prev->next = conn->next;
1001 kfree (conn);
1003 return 1;
1006 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)
1008 *ret = 0;
1009 proto_tcp_conn_t *conn = NULL;
1010 proto_tcp_conn_t *conn_ret = NULL;
1011 //printf ("-------------------------\n");
1012 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1013 /*printf ("-> ");
1014 net_proto_ip_print (conn->ip_source);
1015 printf (" / ");
1016 net_proto_ip_print (ip_source);
1017 printf ("\n2> ");
1018 net_proto_ip_print (conn->ip_dest);
1019 printf (" / ");
1020 net_proto_ip_print (ip_dest);
1021 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
1022 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
1024 if (conn->ip_source == ip_source && conn->port_source == port_source) {
1025 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
1026 *ret = 2;
1027 return conn;
1030 *ret = 1;
1032 conn_ret = conn;
1036 if (*ret == 1)
1037 if (!conn_ret->bind) {
1038 conn_ret = 0;
1040 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1041 if (conn->bind) {
1042 if (conn->ip_source == ip_source && conn->port_source == port_source)
1043 conn_ret = conn;
1048 return conn_ret;
1051 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
1053 proto_tcp_conn_t *conn = NULL;
1054 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1055 if (conn->fd == fd)
1056 return conn;
1059 return 0;
1062 /* Create new TCP backlog stamp */
1063 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
1065 if (!conn)
1066 return 0;
1068 proto_tcp_backlog_t *backlog;
1070 /* alloc and init context */
1071 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
1073 if (!backlog)
1074 return 0;
1076 backlog->conn = conn;
1077 backlog->ip = ip;
1078 backlog->port = port;
1079 backlog->seq = seq;
1081 /* add into list */
1082 backlog->next = &proto_tcp_backlog_list;
1083 backlog->prev = proto_tcp_backlog_list.prev;
1084 backlog->prev->next = backlog;
1085 backlog->next->prev = backlog;
1087 return conn->fd;
1090 /* init of tcp protocol */
1091 unsigned init_net_proto_tcp ()
1093 proto_tcp_conn_list.next = &proto_tcp_conn_list;
1094 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
1096 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
1097 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
1099 proto_tcp_dup = 0x0;
1100 proto_tcp_seq = 0x1;
1102 return 1;